home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 253 / Issue 253 - March 2009 - DPCS0309DVD.ISO / Toolkit / Internet / WinHTTrack / httrack-3.43.exe / {app} / src / htsback.c < prev    next >
Encoding:
C/C++ Source or Header  |  1980-01-01  |  150.9 KB  |  3,909 lines

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20.  
  21. Important notes:
  22.  
  23. - We hereby ask people using this source NOT to use it in purpose of grabbing
  24. emails addresses, or collecting any other private information on persons.
  25. This would disgrace our work, and spoil the many hours we spent on it.
  26.  
  27.  
  28. Please visit our Website: http://www.httrack.com
  29. */
  30.  
  31.  
  32. /* ------------------------------------------------------------ */
  33. /* File: httrack.c subroutines:                                 */
  34. /*       backing system (multiple socket download)              */
  35. /* Author: Xavier Roche                                         */
  36. /* ------------------------------------------------------------ */
  37.  
  38. /* Internal engine bytecode */
  39. #define HTS_INTERNAL_BYTECODE
  40.  
  41. /* specific definitions */
  42. #include "htsnet.h"
  43. #include "htscore.h"
  44. #include "htsthread.h"
  45. #include <time.h>
  46. /* END specific definitions */
  47.  
  48. #include "htsback.h"
  49.  
  50. //#ifdef _WIN32
  51. #include "htsftp.h"
  52. #if HTS_USEZLIB
  53. #include "htszlib.h"
  54. #else
  55. #error HTS_USEZLIB not defined
  56. #endif
  57. //#endif
  58.  
  59. #ifdef _WIN32
  60. #ifndef __cplusplus
  61. // DOS
  62. #ifndef  _WIN32_WCE
  63. #include <process.h>    /* _beginthread, _endthread */
  64. #endif
  65. #endif
  66. #else
  67. #endif
  68.  
  69. #if HTS_USEMMS
  70. #include "htsmms.h"
  71. #endif
  72.  
  73. #undef test_flush
  74. #define test_flush if (opt->flush) { if (opt->log) { fflush(opt->log); } if (opt->log) { fflush(opt->log);  } }
  75.  
  76. #define VT_CLREOL       "\33[K"
  77.  
  78. /* Slot operations */
  79. static int slot_can_be_cached_on_disk(const lien_back* back);
  80. static int slot_can_be_cleaned(const lien_back* back);
  81. static int slot_can_be_finalized(httrackp* opt, const lien_back* back);
  82.  
  83.  
  84. struct_back* back_new(int back_max) {
  85.   int i;
  86.   struct_back* sback = calloct(1, sizeof(struct_back));
  87.   sback->count = back_max;
  88.   sback->lnk = (lien_back*) calloct((back_max + 1), sizeof(lien_back));
  89.   sback->ready = inthash_new(32767);
  90.     sback->ready_size_bytes = 0;
  91.   inthash_value_is_malloc(sback->ready, 1);
  92.   // init
  93.   for(i = 0 ; i < sback->count ; i++){
  94.     sback->lnk[i].r.location = sback->lnk[i].location_buffer;
  95.     sback->lnk[i].status = STATUS_FREE;
  96.     sback->lnk[i].r.soc = INVALID_SOCKET;
  97.   }
  98.   return sback;
  99. }
  100.  
  101. void back_free(struct_back** sback) {
  102.   if (sback != NULL && *sback != NULL) {
  103.     if ((*sback)->lnk != NULL) {
  104.       freet((*sback)->lnk);
  105.       (*sback)->lnk = NULL;
  106.     }
  107.     if ((*sback)->ready != NULL) {
  108.       inthash_delete(&(*sback)->ready);
  109.             (*sback)->ready_size_bytes = 0;
  110.     }
  111.     freet(*sback);
  112.     *sback = NULL;
  113.   }
  114. }
  115.  
  116. void back_delete_all(httrackp* opt, cache_back* cache, struct_back* sback) {
  117.   if (sback != NULL) {
  118.     int i;
  119.     // delete live slots
  120.     for(i = 0 ; i < sback->count ; i++) {
  121.       back_delete(opt, cache, sback, i);
  122.     }
  123.     // delete stored slots
  124.     if (sback->ready != NULL) {
  125.       struct_inthash_enum e = inthash_enum_new(sback->ready);
  126.       inthash_chain* item;
  127.       while((item = inthash_enum_next(&e))) {
  128. #ifndef HTS_NO_BACK_ON_DISK
  129.                 char *filename = (char*) item->value.ptr;
  130.                 if (filename != NULL) {
  131.                     (void) unlink(filename);
  132.                 }
  133. #else
  134.                 /* clear entry content (but not yet the entry) */
  135.                 lien_back *back = (lien_back*) item->value.ptr;
  136.                 back_clear_entry(back);
  137. #endif
  138.       }
  139.             /* delete hashtable & content */
  140.             inthash_delete(&sback->ready);
  141.             sback->ready_size_bytes = 0;
  142.     }
  143.   }
  144. }
  145.  
  146. // ---
  147. // routines de backing
  148.  
  149. static int back_index_ready(httrackp* opt, struct_back* sback, char* adr, char* fil, char* sav, int getIndex);
  150. static int back_index_fetch(httrackp* opt, struct_back* sback, char* adr, char* fil, char* sav, int getIndex);
  151.  
  152. // retourne l'index d'un lien dans un tableau de backing
  153. int back_index(httrackp* opt, struct_back* sback,char* adr,char* fil,char* sav) {
  154.   return back_index_fetch(opt,sback, adr, fil, sav, 1);
  155. }
  156.  
  157. static int back_index_fetch(httrackp* opt, struct_back* sback, char* adr, char* fil, char* sav, int getIndex) {
  158.   lien_back* const back = sback->lnk;
  159.   const int back_max = sback->count;
  160.   int index=-1;
  161.   int i;
  162.   for( i = 0 ; i < back_max ; i++ ) {
  163.     if (back[i].status >= 0        /* not free or alive */
  164.       && strfield2(back[i].url_adr,adr)
  165.       && strcmp(back[i].url_fil,fil)==0) 
  166.     {
  167.       if (index==-1)    /* first time we meet, store it */
  168.         index=i;
  169.       else if (sav != NULL && strcmp(back[i].url_sav, sav) == 0) {  /* oops, check sav too */
  170.         index=i;
  171.         return index;
  172.       }
  173.     }
  174.   }
  175.   // not found in fast repository - search in the storage hashtable
  176.   if (index == -1 && sav != NULL) {
  177.     index = back_index_ready(opt, sback, adr, fil, sav, getIndex);
  178.   }
  179.   return index;
  180. }
  181.  
  182. /* resurrect stored entry */
  183. static int back_index_ready(httrackp* opt, struct_back* sback, char* adr, char* fil, char* sav, int getIndex) {
  184.   lien_back* const back = sback->lnk;
  185.   void* ptr = NULL;
  186.   if (inthash_read_pvoid(sback->ready, sav, &ptr)) {
  187.         if (!getIndex) {        /* don't "pagefault" the entry */
  188.             if (ptr != NULL) {
  189.                 return sback->count;        /* (invalid but) positive result */
  190.             } else {
  191.                 return -1;            /* not found */
  192.       }
  193.     } else if (ptr != NULL) {
  194.       lien_back* itemback = NULL;
  195. #ifndef HTS_NO_BACK_ON_DISK
  196.       FILE *fp;
  197.       char* fileback = (char*) ptr;
  198.         char catbuff[CATBUFF_SIZE];
  199.       if (( fp = fopen(fconv(catbuff, fileback), "rb") ) != NULL ) {
  200.         if (back_unserialize(fp, &itemback) != 0) {
  201.           if (itemback != NULL) {
  202.             back_clear_entry(itemback);
  203.             freet(itemback);
  204.             itemback = NULL;
  205.           }
  206.           if (opt->log != NULL) {
  207.             int last_errno = errno;
  208.             HTS_LOG(opt,LOG_INFO); fprintf(opt->log,"engine: warning: unserialize error for %s%s (%s): %s"LF,adr,fil,sav,strerror(last_errno));
  209.             test_flush;
  210.           }
  211.         }
  212.         fclose(fp);
  213.       } else {
  214.         if (opt->log != NULL) {
  215.           int last_errno = errno;
  216.           HTS_LOG(opt,LOG_INFO); fprintf(opt->log,"engine: warning: unserialize error for %s%s (%s), file disappeared: %s"LF,adr,fil,sav,strerror(last_errno));
  217.           test_flush;
  218.         }
  219.       }
  220.       (void) unlink(fileback);
  221. #else
  222.       itemback = (lien_back*) ptr;
  223. #endif
  224.             if (itemback != NULL) {
  225.                 // move from hashtable to fast repository
  226.                 int q = back_search(opt, sback);
  227.                 if (q != -1) {
  228.                     deletehttp(&back[q].r);               // security check
  229.                     back_move(itemback, &back[q]);
  230.                     back_clear_entry(itemback);                /* delete entry content */
  231.                     freet(itemback);                                    /* delete item */
  232.                     itemback = NULL;
  233.                     inthash_remove(sback->ready, sav);  // delete item
  234.                     sback->ready_size_bytes -= back[q].r.size;  /* substract for stats */
  235.           back_set_locked(sback, q);  /* locked */
  236.                     return q;
  237.         } else {
  238.           if (opt->log != NULL) {
  239.             HTS_LOG(opt,LOG_INFO); fprintf(opt->log,"engine: warning: unserialize error for %s%s (%s): no more space to wakeup frozen slots"LF,adr,fil,sav);
  240.             test_flush;
  241.           }
  242.         }
  243.             }
  244.         }
  245.   }
  246.   return -1;
  247. }
  248.  
  249. static int slot_can_be_cached_on_disk(const lien_back* back) {
  250.   return
  251.     (back->status == STATUS_READY && back->locked == 0 
  252.       && back->url_sav[0] != '\0'
  253.       && strcmp(back->url_sav, BACK_ADD_TEST) != 0
  254.       );
  255.   /* Note: not checking !IS_DELAYED_EXT(back->url_sav) or it will quickly cause the slots to be filled! */
  256. }
  257.  
  258. /* Put all backing entries that are ready in the storage hashtable to spare space and CPU */
  259. int back_cleanup_background(httrackp* opt,cache_back* cache,struct_back* sback) {
  260.   lien_back* const back = sback->lnk;
  261.   const int back_max = sback->count;
  262.   int nclean = 0;
  263.   int i;
  264.   for( i = 0 ;  i < back_max ; i++ ) {
  265.     // ready, not locked and suitable
  266.     if (slot_can_be_cached_on_disk(&back[i])) {
  267. #ifdef HTS_NO_BACK_ON_DISK
  268.       lien_back* itemback;
  269. #endif
  270.       /* Security check */
  271.       int checkIndex = back_index_ready(opt, sback, back[i].url_adr, back[i].url_fil, back[i].url_sav, 1);
  272.       if (checkIndex != -1) {
  273.         if (opt->log) {
  274.           HTS_LOG(opt,LOG_WARNING); fprintf(opt->log,"engine: unexpected duplicate file entry: %s%s -> %s (%d '%s') / %s%s -> %s (%d '%s')"LF,
  275.             back[checkIndex].url_adr, back[checkIndex].url_fil, back[checkIndex].url_sav, back[checkIndex].r.statuscode, back[checkIndex].r.msg,
  276.             back[i].url_adr, back[i].url_fil, back[i].url_sav, back[i].r.statuscode, back[i].r.msg
  277.             );
  278.           test_flush;
  279.         }
  280.         back_delete(NULL, NULL, sback, checkIndex);
  281. #ifdef _DEBUG
  282.         /* This should NOT happend! */
  283.         { int duplicateEntryInBacklog = 1; assertf(!duplicateEntryInBacklog); }
  284. #endif
  285.             }
  286. #ifndef HTS_NO_BACK_ON_DISK
  287.             /* temporarily serialize the entry on disk */
  288.             {
  289.                 int fsz = (int) strlen(back[i].url_sav);
  290.         char *filename = malloc(fsz + 8 + 1);
  291.         if (filename != NULL) {
  292.           FILE *fp;
  293.           if (opt->getmode != 0) {
  294.             sprintf(filename, "%s.tmp", back[i].url_sav);
  295.           } else {
  296.             sprintf(filename, "%stmpfile%d.tmp", StringBuff(opt->path_html), opt->state.tmpnameid++);
  297.           }
  298.           /* Security check */
  299.           if (fexist(filename)) {
  300.             if (opt->log != NULL) {
  301.               HTS_LOG(opt,LOG_INFO); fprintf(opt->log,"engine: warning: temporary file %s already exists"LF, filename);
  302.               test_flush;
  303.             }
  304.           }
  305.           /* Create file and serialize slot */
  306.           if ((fp = filecreate(NULL, filename)) != NULL) 
  307.           {
  308.             if (back_serialize(fp, &back[i]) == 0)
  309.             {
  310.               inthash_add_pvoid(sback->ready, back[i].url_sav, filename);
  311.               filename = NULL;
  312.               sback->ready_size_bytes += back[i].r.size;  /* add for stats */
  313.               nclean++;
  314.               back_clear_entry(&back[i]);            /* entry is now recycled */
  315.             } else {
  316.               if (opt->log != NULL) {
  317.                 int last_errno = errno;
  318.                 HTS_LOG(opt,LOG_INFO); fprintf(opt->log,"engine: warning: serialize error for %s%s to %s: write error: %s"LF,back[i].url_adr,back[i].url_fil,filename,strerror(last_errno));
  319.                 test_flush;
  320.               }
  321.             }
  322.             fclose(fp);
  323.           } else {
  324.             if (opt->log != NULL) {
  325.               int last_errno = errno;
  326.               HTS_LOG(opt,LOG_INFO); fprintf(opt->log,"engine: warning: serialize error for %s%s to %s: open error: %s (%s, %s)"LF, back[i].url_adr, back[i].url_fil, filename, strerror(last_errno), dir_exists(filename) ? "directory exists" : "directory does NOT exist!", fexist(filename) ? "file already exists!" : "file does not exist");
  327.               test_flush;
  328.             }
  329.           }
  330.                     if (filename != NULL)
  331.                         free(filename);
  332.                 } else {
  333.           if (opt->log != NULL) {
  334.             int last_errno = errno;
  335.             HTS_LOG(opt,LOG_INFO); fprintf(opt->log,"engine: warning: serialize error for %s%s to %s: memory full: %s"LF,back[i].url_adr,back[i].url_fil,filename,strerror(last_errno));
  336.             test_flush;
  337.           }
  338.                 }
  339.             }
  340. #else
  341.             itemback = calloct(1, sizeof(lien_back));
  342.       back_move(&back[i], itemback);
  343.       inthash_add_pvoid(sback->ready, itemback->url_sav, itemback);
  344.       nclean++;
  345. #endif
  346.     }
  347.   }
  348.   return nclean;
  349. }
  350.  
  351. // nombre d'entrΘes libres dans le backing
  352. int back_available(struct_back* sback) {
  353.   lien_back* const back = sback->lnk;
  354.   const int back_max = sback->count;
  355.   int i;
  356.   int nb=0;
  357.   for(i=0;i<back_max;i++)
  358.     if (back[i].status==STATUS_FREE)     /* libre */
  359.       nb++;
  360.   return nb;
  361. }
  362.  
  363. // retourne estimation de la taille des html et fichiers stockΘs en mΘmoire
  364. LLint back_incache(struct_back* sback) {
  365.   lien_back* const back = sback->lnk;
  366.   const int back_max = sback->count;
  367.   int i;
  368.   LLint sum=0;
  369.   for(i=0;i<back_max;i++)
  370.     if (back[i].status!=-1)
  371.       if (back[i].r.adr)       // ne comptabilier que les blocs en mΘmoire
  372.         sum+=max(back[i].r.size,back[i].r.totalsize);
  373.   // stored (ready) slots
  374. #ifdef HTS_NO_BACK_ON_DISK
  375.   if (sback->ready != NULL) {
  376.     struct_inthash_enum e = inthash_enum_new(sback->ready);
  377.     inthash_chain* item;
  378.     while((item = inthash_enum_next(&e))) {
  379.       lien_back* ritem = (lien_back*) item->value.ptr;
  380.       if (ritem->status!=-1)
  381.         if (ritem->r.adr)       // ne comptabilier que les blocs en mΘmoire
  382.           sum+=max(ritem->r.size,ritem->r.totalsize);
  383.     }
  384.   }
  385. #endif
  386.   return sum;
  387. }
  388.  
  389. // retourne estimation de la taille des html et fichiers stockΘs en mΘmoire
  390. int back_done_incache(struct_back* sback) {
  391.   lien_back* const back = sback->lnk;
  392.   const int back_max = sback->count;
  393.   int i;
  394.   int n = 0;
  395.   for(i = 0 ; i < back_max ; i++)
  396.     if (back[i].status == STATUS_READY)
  397.       n++;
  398.   // stored (ready) slots
  399.   if (sback->ready != NULL) {
  400. #ifndef HTS_NO_BACK_ON_DISK
  401.         n += inthash_nitems(sback->ready);
  402. #else
  403.         struct_inthash_enum e = inthash_enum_new(sback->ready);
  404.     inthash_chain* item;
  405.     while((item = inthash_enum_next(&e))) {
  406.       lien_back* ritem = (lien_back*) item->value.ptr;
  407.       if (ritem->status==STATUS_READY)
  408.         n++;
  409.     }
  410. #endif
  411.   }
  412.   return n;
  413. }
  414.  
  415.  
  416. // le lien a-t-il ΘtΘ mis en backing?
  417. HTS_INLINE int back_exist(struct_back* sback,httrackp* opt,char* adr,char* fil,char* sav) {
  418.   return (back_index_fetch(opt, sback, adr, fil, sav, /*don't fetch*/0) >= 0);
  419. }
  420.  
  421. // nombre de sockets en tΓche de fond
  422. int back_nsoc(struct_back* sback) {
  423.   lien_back* const back = sback->lnk;
  424.   const int back_max = sback->count;
  425.   int n=0;
  426.   int i;
  427.   for(i=0;i<back_max;i++)
  428.     if (back[i].status > 0)    // only receive
  429.       n++;
  430.  
  431.   return n;
  432. }
  433. int back_nsoc_overall(struct_back* sback) {
  434.   lien_back* const back = sback->lnk;
  435.   const int back_max = sback->count;
  436.   int n=0;
  437.   int i;
  438.   for(i=0;i<back_max;i++)
  439.     if (back[i].status > 0 || back[i].status == STATUS_ALIVE)
  440.       n++;
  441.  
  442.   return n;
  443. }
  444.  
  445. // objet (lien) tΘlΘchargΘ ou transfΘrΘ depuis le cache
  446. //
  447. // fermer les paramΦtres de transfert,
  448. // et notamment vΘrifier les fichiers compressΘs (dΘcompresser), callback etc.
  449. int back_finalize(httrackp* opt,cache_back* cache,struct_back* sback,int p) {
  450.     char catbuff[CATBUFF_SIZE];
  451.   lien_back* const back = sback->lnk;
  452.   const int back_max = sback->count;
  453.   assertf(p >= 0 && p < back_max);
  454.  
  455.     /* Store ? */
  456.     if (!back[p].finalized) {
  457.         back[p].finalized = 1;
  458.  
  459.         /* Don't store broken files */
  460.         if (back[p].r.totalsize > 0 && back[p].r.size != back[p].r.totalsize && ! opt->tolerant) {
  461.             return -1;
  462.         }
  463.  
  464.         if (
  465.             (back[p].status == STATUS_READY)      // ready
  466.             &&
  467.             (back[p].r.statuscode > 0)   // not internal error
  468.             ) 
  469.         {
  470.             if (!back[p].testmode) {        // not test mode
  471.                 char* state="unknown";
  472.  
  473.                 /* dΘcompression */
  474. #if HTS_USEZLIB
  475.                 if (gz_is_available && back[p].r.compressed) {
  476.                     if (back[p].r.size > 0) {
  477.                         //if ( (back[p].r.adr) && (back[p].r.size>0) ) {
  478.                         // stats
  479.                         back[p].compressed_size=back[p].r.size;
  480.                         // en mΘmoire -> passage sur disque
  481.                         if (!back[p].r.is_write) {
  482.                             back[p].tmpfile_buffer[0]='\0';
  483.                             back[p].tmpfile=tmpnam(back[p].tmpfile_buffer);
  484.                             if (back[p].tmpfile != NULL && back[p].tmpfile[0] != '\0') {
  485.                                 back[p].r.out=fopen(back[p].tmpfile,"wb");
  486.                                 if (back[p].r.out) {
  487.                                     if ((back[p].r.adr) && (back[p].r.size>0)) {
  488.                                         if (fwrite(back[p].r.adr,1,(size_t)back[p].r.size,back[p].r.out) != back[p].r.size) {
  489.                                             back[p].r.statuscode=STATUSCODE_INVALID;
  490.                                             strcpybuff(back[p].r.msg,"Write error when decompressing");
  491.                                         }
  492.                                     } else {
  493.                                         back[p].tmpfile[0]='\0';
  494.                                         back[p].r.statuscode=STATUSCODE_INVALID;
  495.                                         strcpybuff(back[p].r.msg,"Empty compressed file");
  496.                                     }
  497.                                 } else {
  498.                                     back[p].tmpfile[0]='\0';
  499.                                     back[p].r.statuscode=STATUSCODE_INVALID;
  500.                                     strcpybuff(back[p].r.msg,"Open error when decompressing");
  501.                                 }
  502.                             }
  503.                         }
  504.                         // fermer fichier sortie
  505.                         if (back[p].r.out!=NULL) {
  506.                             fclose(back[p].r.out);
  507.                             back[p].r.out=NULL;
  508.                         }
  509.                         // dΘcompression
  510.                         if (back[p].tmpfile != NULL && back[p].tmpfile[0] != '\0') {
  511.                             if (back[p].url_sav[0]) {
  512.                                 LLint size;
  513.                                 file_notify(opt,back[p].url_adr, back[p].url_fil, back[p].url_sav, 1, 1, back[p].r.notmodified);
  514.                                 filecreateempty(&opt->state.strc, back[p].url_sav);      // filenote & co
  515.                                 if ((size = hts_zunpack(back[p].tmpfile,back[p].url_sav))>=0) {
  516.                                     back[p].r.size=back[p].r.totalsize=size;
  517.                                     // fichier -> mΘmoire
  518.                                     if (!back[p].r.is_write) {
  519.                                         deleteaddr(&back[p].r);
  520.                                         back[p].r.adr=readfile(back[p].url_sav);
  521.                                         if (!back[p].r.adr) {
  522.                                             back[p].r.statuscode=STATUSCODE_INVALID;
  523.                                             strcpybuff(back[p].r.msg,"Read error when decompressing");
  524.                                         }
  525.                                         unlink(back[p].url_sav);
  526.                                     }
  527.                                 }
  528.                             }
  529.                             /* encore that no remaining temporary file exists */
  530.                             unlink(back[p].tmpfile);
  531.                             back[p].tmpfile = NULL;
  532.                         }
  533.                         // stats
  534.                         HTS_STAT.total_packed+=back[p].compressed_size;
  535.                         HTS_STAT.total_unpacked+=back[p].r.size;
  536.                         HTS_STAT.total_packedfiles++;
  537.                         // unflag
  538.                     }
  539.                 }
  540.                 back[p].r.compressed=0;
  541. #endif
  542.  
  543.                 /* Write mode to disk */
  544.                 if (back[p].r.is_write && back[p].r.adr != NULL) {
  545.                     freet(back[p].r.adr);
  546.                     back[p].r.adr = NULL;
  547.                 }
  548.  
  549.         /* remove reference file, if any */
  550.         if (back[p].r.is_write) {
  551.           url_savename_refname_remove(opt, back[p].url_adr, back[p].url_fil);
  552.         }
  553.  
  554.                 /* ************************************************************************
  555.                     REAL MEDIA HACK
  556.                     Check if we have to load locally the file
  557.                 ************************************************************************ */
  558.                 if (back[p].r.statuscode == HTTP_OK) {    // OK (ou 304 en backing)
  559.                     if (back[p].r.is_write) {    // Written file
  560.                         if (may_be_hypertext_mime(opt,back[p].r.contenttype, back[p].url_fil)) {   // to parse!
  561.                             off_t sz;
  562.                             sz=fsize(back[p].url_sav);
  563.                             if (sz>0) {   // ok, exists!
  564.                                 if (sz < 8192) {   // ok, small file --> to parse!
  565.                                     FILE* fp=fopen(back[p].url_sav,"rb");
  566.                                     if (fp) {
  567.                                         back[p].r.adr=malloct((int)sz + 2);
  568.                                         if (back[p].r.adr) {
  569.                                             if (fread(back[p].r.adr,1,sz,fp) == sz) {
  570.                                                 back[p].r.size=sz;
  571.                                                 back[p].r.adr[sz] = '\0';
  572.                                                 back[p].r.is_write = 0;                /* not anymore a direct-to-disk file */
  573.                                             } else {
  574.                                                 freet(back[p].r.adr);
  575.                                                 back[p].r.size=0;
  576.                                                 back[p].r.adr = NULL;
  577.                                                 back[p].r.statuscode=STATUSCODE_INVALID;
  578.                                                 strcpybuff(back[p].r.msg, ".RAM read error");
  579.                                             }
  580.                                             fclose(fp);
  581.                                             fp=NULL;
  582.                                             // remove (temporary) file!
  583.                                             unlink(fconv(catbuff,back[p].url_sav));
  584.                                         }
  585.                                         if (fp)
  586.                                             fclose(fp);
  587.                                     }
  588.                                 }
  589.                             }
  590.                         }
  591.                     }
  592.                 }
  593.                 /* EN OF REAL MEDIA HACK */
  594.  
  595.  
  596.                 /* Stats */
  597.                 if (cache->txt) {
  598.                     char flags[32];
  599.                     char s[256];
  600.                     time_t tt;
  601.                     struct tm* A;
  602.                     tt=time(NULL);
  603.                     A=localtime(&tt);
  604.                     if (A == NULL) {
  605.                         int localtime_returned_null=0;
  606.                         assert(localtime_returned_null);
  607.                     }
  608.                     strftime(s,250,"%H:%M:%S",A);
  609.  
  610.                     flags[0]='\0';
  611.                     /* input flags */
  612.                     if (back[p].is_update)
  613.                         strcatbuff(flags, "U");   // update request
  614.                     else
  615.                         strcatbuff(flags, "-");
  616.                     if (back[p].range_req_size)
  617.                         strcatbuff(flags, "R");   // range request
  618.                     else
  619.                         strcatbuff(flags, "-");
  620.                     /* state flags */
  621.                     if (back[p].r.is_file)  // direct to disk
  622.                         strcatbuff(flags, "F");
  623.                     else
  624.                         strcatbuff(flags, "-");
  625.                     /* output flags */
  626.                     if (!back[p].r.notmodified)
  627.                         strcatbuff(flags, "M");   // modified
  628.                     else
  629.                         strcatbuff(flags, "-");
  630.                     if (back[p].r.is_chunk)  // chunked
  631.                         strcatbuff(flags, "C");
  632.                     else
  633.                         strcatbuff(flags, "-");
  634.                     if (back[p].r.compressed)
  635.                         strcatbuff(flags, "Z");   // gzip
  636.                     else
  637.                         strcatbuff(flags, "-");
  638.                     /* Err I had to split these.. */
  639.                     fprintf(cache->txt,"%s\t", s);
  640.                     fprintf(cache->txt,LLintP"/", (LLint)back[p].r.size);
  641.                     fprintf(cache->txt,LLintP,(LLint)back[p].r.totalsize);
  642.                     fprintf(cache->txt,"\t%s\t",flags);
  643.                 }
  644.                 if (back[p].r.statuscode == HTTP_OK) {
  645.                     if (back[p].r.size>=0) {
  646.                         if (strcmp(back[p].url_fil,"/robots.txt") !=0 ) {
  647.                             HTS_STAT.stat_bytes+=back[p].r.size;
  648.                             HTS_STAT.stat_files++;
  649.                         }
  650.                         if ( (!back[p].r.notmodified) && (opt->is_update) ) { 
  651.                             HTS_STAT.stat_updated_files++;       // page modifiΘe
  652.                             if (opt->log!=NULL) {
  653.                                 HTS_LOG(opt,LOG_INFO);
  654.                                 if (back[p].is_update) {
  655.                                     fprintf(opt->log,"engine: transfer-status: link updated: %s%s -> %s"LF,back[p].url_adr,back[p].url_fil,back[p].url_sav);
  656.                                 } else {
  657.                                     fprintf(opt->log,"engine: transfer-status: link added: %s%s -> %s"LF,back[p].url_adr,back[p].url_fil,back[p].url_sav);
  658.                                 }
  659.                                 test_flush;
  660.                             }
  661.                             if (cache->txt) {
  662.                                 if (back[p].is_update) {
  663.                                     state="updated";
  664.                                 } else {
  665.                                     state="added";
  666.                                 }
  667.                             }
  668.                         } else {
  669.                             if ( (opt->debug>0) && (opt->log!=NULL) ) {
  670.                                 HTS_LOG(opt,LOG_INFO); fprintf(opt->log,"engine: transfer-status: link recorded: %s%s -> %s"LF,back[p].url_adr,back[p].url_fil,back[p].url_sav);
  671.                                 test_flush;
  672.                             }
  673.                             if (cache->txt) {
  674.                                 if (opt->is_update)
  675.                                     state="untouched";
  676.                                 else
  677.                                     state="added";
  678.                             }
  679.                         }
  680.                     } else {
  681.                         if ( (opt->debug>0) && (opt->log!=NULL) ) {
  682.                             HTS_LOG(opt,LOG_INFO); fprintf(opt->log,"engine: transfer-status: empty file? (%d, '%s'): %s%s"LF,back[p].r.statuscode,back[p].r.msg,back[p].url_adr,back[p].url_fil);
  683.                             test_flush;
  684.                         }
  685.                         if (cache->txt) {
  686.                             state="empty";
  687.                         }
  688.                     }
  689.                 } else {
  690.                     if ( (opt->debug>0) && (opt->log!=NULL) ) {
  691.                         HTS_LOG(opt,LOG_INFO); fprintf(opt->log,"engine: transfer-status: link error (%d, '%s'): %s%s"LF,back[p].r.statuscode,back[p].r.msg,back[p].url_adr,back[p].url_fil);
  692.                     }
  693.                     if (cache->txt) {
  694.                         state="error";
  695.                     }
  696.                 }
  697.                 if (cache->txt) {
  698.                     fprintf(cache->txt,
  699.                         "%d\t"
  700.                         "%s ('%s')\t"
  701.                         "%s\t"
  702.                         "%s%s\t"
  703.                         "%s%s%s\t%s\t"
  704.                         "(from %s%s%s)"
  705.                         LF,
  706.                         back[p].r.statuscode,
  707.                         state, escape_check_url_addr(OPT_GET_BUFF(opt),back[p].r.msg),
  708.                         escape_check_url_addr(OPT_GET_BUFF(opt),back[p].r.contenttype),
  709.                         ((back[p].r.etag[0])?"etag:":((back[p].r.lastmodified[0])?"date:":"")), escape_check_url_addr(OPT_GET_BUFF(opt),(back[p].r.etag[0])?back[p].r.etag:(back[p].r.lastmodified)),
  710.                         (link_has_authority(back[p].url_adr) ? "" : "http://"),escape_check_url_addr(OPT_GET_BUFF(opt),back[p].url_adr),escape_check_url_addr(OPT_GET_BUFF(opt),back[p].url_fil),escape_check_url_addr(OPT_GET_BUFF(opt),back[p].url_sav),
  711.                         (link_has_authority(back[p].referer_adr) || !back[p].referer_adr[0]) ? "" : "http://",escape_check_url_addr(OPT_GET_BUFF(opt),back[p].referer_adr),escape_check_url_addr(OPT_GET_BUFF(opt),back[p].referer_fil)
  712.                         );
  713.                     if (opt->flush)
  714.                         fflush(cache->txt);
  715.                 }
  716.  
  717.                 /* Cache */
  718.                 if (!IS_DELAYED_EXT(back[p].url_sav)) {
  719.                     cache_mayadd(opt,cache,&back[p].r,back[p].url_adr,back[p].url_fil,back[p].url_sav);
  720.                 } else {
  721.                     if (!HTTP_IS_OK(back[p].r.statuscode)) {
  722.                         if ( (opt->debug>0) && (opt->log!=NULL) ) {
  723.                             HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"redirect to %s%s"LF,back[p].url_adr,back[p].url_fil);
  724.                         }
  725.                         /* Store only header reference */
  726.                         cache_mayadd(opt,cache,&back[p].r,back[p].url_adr,back[p].url_fil,NULL);
  727.                     } else {
  728.             /* Partial file, but marked as "ok" ? */
  729.                         if (opt->log!=NULL) {
  730.                             HTS_LOG(opt,LOG_WARNING); fprintf(opt->log,"file not stored in cache due to bogus state (incomplete type): %s%s"LF,back[p].url_adr,back[p].url_fil);
  731.                         }
  732.                     }
  733.                 }
  734.  
  735.                 // status finished callback
  736.             RUN_CALLBACK1(opt, xfrstatus, &back[p]);
  737.  
  738.                 return 0;
  739.             } else {        // testmode
  740.                 if (back[p].r.statuscode / 100 >= 3) {        /* Store 3XX, 4XX, 5XX test response codes, but NOT 2XX */
  741.                     /* Cache */
  742.                     cache_mayadd(opt,cache,&back[p].r,back[p].url_adr,back[p].url_fil,NULL);
  743.                 }
  744.             }
  745.         }
  746.     }
  747.     return -1;
  748. }
  749.  
  750. /* try to keep the connection alive */
  751. int back_letlive(httrackp* opt, cache_back* cache, struct_back* sback, int p) {
  752.     lien_back* const back = sback->lnk;
  753.     const int back_max = sback->count;
  754.     int checkerror;
  755.     htsblk* src = &back[p].r;
  756.     assertf(p >= 0 && p < back_max);
  757.     if (src && !src->is_file 
  758.         && src->soc != INVALID_SOCKET
  759.         && src->statuscode >= 0           /* no timeout errors & co */
  760.         && src->keep_alive_trailers == 0  /* not yet supported (chunk trailers) */
  761.         && ! ( checkerror = check_sockerror(src->soc) )
  762.         /*&& !check_sockdata(src->soc)*/     /* no unexpected data */
  763.         ) {
  764.             htsblk tmp;
  765.             memset(&tmp, 0, sizeof(tmp));
  766.             /* clear everything but connection: switch, close, and reswitch */
  767.             back_connxfr(src, &tmp);
  768.             back_delete(opt, cache, sback, p);
  769.             //deletehttp(src);
  770.             back_connxfr(&tmp, src);
  771.             src->req.flush_garbage=1;     /* ignore CRLF garbage */
  772.             return 1;
  773.         }
  774.         return 0;
  775. }
  776.  
  777. void back_connxfr(htsblk* src, htsblk* dst) {
  778.   dst->soc = src->soc;
  779.   src->soc = INVALID_SOCKET;
  780. #if HTS_USEOPENSSL
  781.   dst->ssl = src->ssl;
  782.   src->ssl = 0;
  783.   dst->ssl_con = src->ssl_con;
  784.   src->ssl_con = NULL;
  785. #endif
  786.   dst->keep_alive = src->keep_alive;
  787.   src->keep_alive = 0;
  788.   dst->keep_alive_max = src->keep_alive_max;
  789.   src->keep_alive_max = 0;
  790.   dst->keep_alive_t = src->keep_alive_t;
  791.   src->keep_alive_t = 0;
  792.   dst->debugid = src->debugid;
  793.   src->debugid = 0;
  794. }
  795.  
  796. void back_move(lien_back* src, lien_back* dst) {
  797.   memcpy(dst, src, sizeof(lien_back));
  798.   memset(src, 0, sizeof(lien_back));  
  799.   src->r.soc=INVALID_SOCKET;
  800.   src->status=STATUS_FREE;
  801.   src->r.location = src->location_buffer;
  802.   dst->r.location = dst->location_buffer;
  803. }
  804.  
  805. void back_copy_static(const lien_back* src, lien_back* dst) {
  806.   memcpy(dst, src, sizeof(lien_back));
  807.   dst->r.soc=INVALID_SOCKET;
  808.     dst->r.adr = NULL;
  809.     dst->r.headers = NULL;
  810.     dst->r.out = NULL;
  811.   dst->r.location = dst->location_buffer;
  812.     dst->r.fp = NULL;
  813. #if HTS_USEOPENSSL
  814.     dst->r.ssl_con = NULL;
  815. #endif
  816. }
  817.  
  818. static int back_data_serialize(FILE *fp, const void *data, size_t size) {
  819.     if ( fwrite(&size, 1, sizeof(size), fp) == sizeof(size)
  820.         && ( size == 0 || fwrite(data, 1, size, fp) == size )
  821.         )
  822.         return 0;
  823.     return 1;    /* error */
  824. }
  825.  
  826. static int back_string_serialize(FILE *fp, const char *str) {
  827.     size_t size = ( str != NULL ) ? ( strlen(str) + 1 ) : 0;
  828.     return back_data_serialize(fp, str, size);
  829. }
  830.  
  831. static int back_data_unserialize(FILE *fp, void **str, size_t *size) {
  832.     *str = NULL;
  833.     if (fread(size, 1, sizeof(*size), fp) == sizeof(*size)) {
  834.         if (*size == 0)            /* serialized NULL ptr */
  835.             return 0;
  836.         *str = malloct(*size + 1);
  837.         if (*str == NULL)
  838.             return 1;        /* error */
  839.         ((char*) *str)[*size] = 0;        /* guard byte */
  840.         if (fread(*str, 1, *size, fp) == *size)
  841.             return 0;
  842.     }
  843.     return 1;        /* error */
  844. }
  845.  
  846. static int back_string_unserialize(FILE *fp, char **str) {
  847.     size_t dummy;
  848.     return back_data_unserialize(fp, (void**) str, &dummy);
  849. }
  850.  
  851. int back_serialize(FILE *fp, const lien_back* src) {
  852.     if (back_data_serialize(fp, src, sizeof(lien_back)) == 0
  853.         && back_data_serialize(fp, src->r.adr, src->r.adr ? (size_t)src->r.size : 0) == 0
  854.         && back_string_serialize(fp, src->r.headers) == 0
  855.         && fflush(fp) == 0)
  856.         return 0;
  857.     return 1;
  858. }
  859.  
  860. int back_unserialize(FILE *fp, lien_back** dst) {
  861.     size_t size;
  862.     *dst = NULL;
  863.   errno = 0;
  864.     if (back_data_unserialize(fp, (void**) dst, &size) == 0 && size == sizeof(lien_back)) {
  865.         (*dst)->tmpfile = NULL;
  866.         (*dst)->chunk_adr = NULL;
  867.         (*dst)->r.adr = NULL;
  868.         (*dst)->r.out = NULL;
  869.         (*dst)->r.location = (*dst)->location_buffer;
  870.         (*dst)->r.fp = NULL;
  871. #if HTS_USEOPENSSL
  872.         (*dst)->r.ssl_con = NULL;
  873. #endif
  874.         if (back_data_unserialize(fp, (void**) &(*dst)->r.adr, &size) == 0) 
  875.         {
  876.             (*dst)->r.size = size;
  877.             (*dst)->r.headers = NULL;
  878.             if (back_string_unserialize(fp, &(*dst)->r.headers) == 0)
  879.                 return 0;        /* ok */
  880.             if ((*dst)->r.headers != NULL)
  881.                 freet((*dst)->r.headers);
  882.         }
  883.         if ((*dst)->r.adr != NULL)
  884.             freet((*dst)->r.adr);
  885.     }
  886.     if (dst != NULL)
  887.         freet(dst);
  888.     *dst = NULL;
  889.     return 1;        /* error */
  890. }
  891.  
  892. /* serialize a reference ; used to store references of files being downloaded in case of broken download */
  893. int back_serialize_ref(httrackp* opt, const lien_back* src) {
  894.   char *filename = url_savename_refname_fullpath(opt, src->url_adr, src->url_fil);
  895.   FILE *fp = fopen(filename, "wb");
  896.   if (fp == NULL) {
  897. #ifdef _WIN32
  898.     if (mkdir(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log), CACHE_REFNAME)) == 0)
  899. #else
  900.     if (mkdir(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log), CACHE_REFNAME), S_IRWXU | S_IRWXG | S_IRWXO) == 0)
  901. #endif
  902.     {
  903.       filename = url_savename_refname_fullpath(opt, src->url_adr, src->url_fil);
  904.       fp = fopen(filename, "wb");
  905.     }
  906.   }
  907.   if (fp != NULL) {
  908.     int ser = back_serialize(fp, src);
  909.     fclose(fp);
  910.     return ser;
  911.   }
  912.   return 1;
  913. }
  914.  
  915. /* unserialize a reference ; used to store references of files being downloaded in case of broken download */
  916. int back_unserialize_ref(httrackp* opt, const char *adr, const char *fil, lien_back** dst) {
  917.   char *filename = url_savename_refname_fullpath(opt, adr, fil);
  918.   FILE *fp = fopen(filename, "rb");
  919.   if (fp != NULL) {
  920.     int ser = back_unserialize(fp, dst);
  921.     fclose(fp);
  922.     if (ser != 0) {                 /* back_unserialize_ref() != 0 does not need cleaning up */
  923.       back_clear_entry(*dst);                /* delete entry content */
  924.       freet(*dst);                                    /* delete item */
  925.       *dst = NULL;
  926.     }
  927.     return ser;
  928.   }
  929.   return 1;
  930. }
  931.  
  932. // clear, or leave for keep-alive
  933. int back_maydelete(httrackp* opt,cache_back* cache,struct_back* sback, int p) {
  934.   lien_back* const back = sback->lnk;
  935.   const int back_max = sback->count;
  936.   assertf(p >= 0 && p < back_max);
  937.   if (p >= 0 && p < back_max) {    // on sait jamais..
  938.     if (
  939.       /* Keep-alive authorized by user */
  940.       !opt->nokeepalive
  941.       /* Socket currently is keep-alive! */
  942.       && back[p].r.keep_alive 
  943.       /* Remaining authorized requests */
  944.       && back[p].r.keep_alive_max > 1
  945.       /* Known keep-alive start (security) */
  946.       && back[p].ka_time_start 
  947.       /* We're on time */
  948.       && time_local() < back[p].ka_time_start + back[p].r.keep_alive_t
  949.       /* Connection delay must not exceed keep-alive timeout */
  950.       && ( opt->maxconn <= 0 || ( back[p].r.keep_alive_t > ( 1.0 / opt->maxconn ) ) )
  951.       ) {
  952.       lien_back tmp;
  953.       strcpybuff(tmp.url_adr, back[p].url_adr);
  954.       if (back_letlive(opt, cache, sback, p)) {
  955.         strcpybuff(back[p].url_adr, tmp.url_adr);
  956.         back[p].status = STATUS_ALIVE;  // alive & waiting
  957.         if ((opt->debug>1) && (opt->log!=NULL)) {
  958.           HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"(Keep-Alive): successfully saved #%d (%s)"LF, 
  959.             back[p].r.debugid,
  960.             back[p].url_adr); test_flush;
  961.         }
  962.         return 1;
  963.       }
  964.     }
  965.     back_delete(opt,cache,sback, p);
  966.   }
  967.   return 0;
  968. }
  969.  
  970. // clear, or leave for keep-alive
  971. void back_maydeletehttp(httrackp* opt, cache_back* cache, struct_back* sback, int p) {
  972.   lien_back* const back = sback->lnk;
  973.   const int back_max = sback->count;
  974.   TStamp lt = 0;
  975.   assertf(p >= 0 && p < back_max);
  976.   if (back[p].r.soc!=INVALID_SOCKET) {
  977.     int q;
  978.     if (
  979.       back[p].r.soc != INVALID_SOCKET        /* security check */
  980.       && back[p].r.statuscode >= 0           /* no timeout errors & co */
  981.       && back[p].r.keep_alive_trailers == 0  /* not yet supported (chunk trailers) */
  982.       /* Socket not in I/O error status */
  983.       && !back[p].r.is_file
  984.       && !check_sockerror(back[p].r.soc)
  985.       /* Keep-alive authorized by user */
  986.       && !opt->nokeepalive
  987.       /* Socket currently is keep-alive! */
  988.       && back[p].r.keep_alive 
  989.       /* Remaining authorized requests */
  990.       && back[p].r.keep_alive_max > 1
  991.       /* Known keep-alive start (security) */
  992.       && back[p].ka_time_start 
  993.       /* We're on time */
  994.       && ( lt = time_local() ) < back[p].ka_time_start + back[p].r.keep_alive_t
  995.       /* Connection delay must not exceed keep-alive timeout */
  996.       && ( opt->maxconn <= 0 || ( back[p].r.keep_alive_t > ( 1.0 / opt->maxconn ) ) )
  997.       /* Available slot in backing */
  998.       && ( q = back_search(opt, sback) ) >= 0
  999.       ) 
  1000.     {
  1001.       lien_back tmp;
  1002.       strcpybuff(tmp.url_adr, back[p].url_adr);
  1003.       deletehttp(&back[q].r);               // security check
  1004.       back_connxfr(&back[p].r, &back[q].r); // transfer live connection settings from p to q
  1005.       back[q].ka_time_start = back[p].ka_time_start;  // refresh
  1006.       back[p].r.soc = INVALID_SOCKET;
  1007.       strcpybuff(back[q].url_adr, tmp.url_adr); // address
  1008.       back[q].status = STATUS_ALIVE;  // alive & waiting
  1009.       if ((opt->debug>1) && (opt->log!=NULL)) {
  1010.         HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"(Keep-Alive): successfully preserved #%d (%s)"LF, 
  1011.           back[q].r.debugid,
  1012.           back[q].url_adr); test_flush;
  1013.       }
  1014.     } else {
  1015.       deletehttp(&back[p].r);
  1016.       back[p].r.soc = INVALID_SOCKET;
  1017.     }
  1018.   }
  1019. }
  1020.  
  1021.  
  1022. /* attempt to attach a live connection to this slot */
  1023. int back_trylive(httrackp* opt,cache_back* cache,struct_back* sback, int p) {
  1024.   lien_back* const back = sback->lnk;
  1025.   const int back_max = sback->count;
  1026.   assertf(p >= 0 && p < back_max);
  1027.   if (p>=0 && back[p].status != STATUS_ALIVE) {     // we never know..
  1028.     int i = back_searchlive(opt,sback, back[p].url_adr);   // search slot
  1029.     if (i >= 0 && i != p) {
  1030.       deletehttp(&back[p].r);               // security check
  1031.       back_connxfr(&back[i].r, &back[p].r); // transfer live connection settings from i to p
  1032.       back_delete(opt,cache,sback, i);      // delete old slot
  1033.       back[p].status=STATUS_CONNECTING;     // ready to connect
  1034.       return 1;                             // success: will reuse live connection
  1035.     }
  1036.   }
  1037.   return 0;
  1038. }
  1039.  
  1040. /* search for a live position, or, if not possible, try to return a new one */
  1041. int back_searchlive(httrackp* opt, struct_back* sback, char* search_addr) {
  1042.   lien_back* const back = sback->lnk;
  1043.   const int back_max = sback->count;
  1044.   int i;
  1045.  
  1046.   /* search for a live socket */
  1047.   for(i = 0 ; i < back_max ; i++ ) {
  1048.     if (back[i].status == STATUS_ALIVE) {
  1049.       if (strfield2(back[i].url_adr, search_addr)) {   /* same location (xxc: check also virtual hosts?) */
  1050.         if (time_local() < back[i].ka_time_start + back[i].r.keep_alive_t) {
  1051.           return i;
  1052.         }
  1053.       }
  1054.     }
  1055.   }
  1056.   return -1;
  1057. }
  1058.   
  1059. int back_search_quick(struct_back* sback) {
  1060.   lien_back* const back = sback->lnk;
  1061.   const int back_max = sback->count;
  1062.   int i;
  1063.  
  1064.   /* try to find an empty place */
  1065.   for(i = 0 ; i < back_max ; i++ ) {
  1066.     if (back[i].status == STATUS_FREE) {
  1067.       return i;
  1068.     }
  1069.   }
  1070.  
  1071.   /* oops, can't find a place */
  1072.   return -1;
  1073. }
  1074.  
  1075. int back_search(httrackp* opt,struct_back* sback) {
  1076.   lien_back* const back = sback->lnk;
  1077.   const int back_max = sback->count;
  1078.   int i;
  1079.  
  1080.   /* try to find an empty place */
  1081.   if ( ( i = back_search_quick(sback) ) != -1)
  1082.     return i;
  1083.  
  1084.   /* couldn't find an empty place, try to requisition a keep-alive place */
  1085.   for(i = 0 ; i < back_max ; i++ ) {
  1086.     if (back[i].status == STATUS_ALIVE) {
  1087.       lien_back* const back = sback->lnk;
  1088.       /* close this place */
  1089.       back_clear_entry(&back[i]);   /* Already finalized (this is the night of the living dead) */
  1090.       /*back_delete(opt,cache,sback, i);*/
  1091.       return i;
  1092.     }
  1093.   }
  1094.  
  1095.   /* oops, can't find a place */
  1096.   return -1;
  1097. }
  1098.  
  1099. void back_set_finished(struct_back* sback, int p) {
  1100.   lien_back* const back = sback->lnk;
  1101.   const int back_max = sback->count;
  1102.   assertf(p >= 0 && p < back_max);
  1103.   if (p >= 0 && p < sback->count) {    // we never know..
  1104.     /* status: finished (waiting to be validated) */
  1105.     back[p].status=STATUS_READY;     /* finished */
  1106.     /* close open r/w streams, if any */
  1107.     if (back[p].r.fp!=NULL) {
  1108.       fclose(back[p].r.fp);
  1109.       back[p].r.fp=NULL;
  1110.     }
  1111.     if (back[p].r.out!=NULL) {  // fermer fichier sortie
  1112.       fclose(back[p].r.out);
  1113.       back[p].r.out=NULL;
  1114.     }
  1115.   }
  1116. }
  1117.  
  1118. void back_set_locked(struct_back* sback, int p) {
  1119.   lien_back* const back = sback->lnk;
  1120.   const int back_max = sback->count;
  1121.   assertf(p >= 0 && p < back_max);
  1122.   if (p >= 0 && p < sback->count) {
  1123.     /* status: locked (in process, do not swap on disk) */
  1124.     back[p].locked = 1;     /* locked */
  1125.   }
  1126. }
  1127.  
  1128. void back_set_unlocked(struct_back* sback, int p) {
  1129.   lien_back* const back = sback->lnk;
  1130.   const int back_max = sback->count;
  1131.   assertf(p >= 0 && p < back_max);
  1132.   if (p >= 0 && p < sback->count) {
  1133.     /* status: unlocked (can be swapped on disk) */
  1134.     back[p].locked = 0;     /* unlocked */
  1135.   }
  1136. }
  1137.  
  1138. int back_flush_output(httrackp* opt, cache_back* cache, struct_back* sback, int p) {
  1139.   lien_back* const back = sback->lnk;
  1140.   const int back_max = sback->count;
  1141.   assertf(p >= 0 && p < back_max);
  1142.   if (p >= 0 && p < sback->count) {    // on sait jamais..
  1143.         /* close input file */
  1144.         if (back[p].r.fp!=NULL) {
  1145.       fclose(back[p].r.fp);
  1146.       back[p].r.fp=NULL;
  1147.     }
  1148.     /* fichier de sortie */
  1149.     if (back[p].r.out!=NULL) {  // fermer fichier sortie
  1150.       fclose(back[p].r.out);
  1151.       back[p].r.out=NULL;
  1152.     }
  1153.         /* set file time */
  1154.     if (back[p].r.is_write) {     // ecriture directe
  1155.       /* Θcrire date "remote" */
  1156.       if (strnotempty(back[p].url_sav)
  1157.                 && strnotempty(back[p].r.lastmodified)
  1158.                 && fexist(back[p].url_sav))          // normalement existe si on a un fichier de sortie
  1159.             {
  1160.         set_filetime_rfc822(back[p].url_sav,back[p].r.lastmodified);
  1161.             }
  1162.       /* executer commande utilisateur aprΦs chargement du fichier */
  1163.       //xx usercommand(opt,0,NULL,back[p].url_sav, back[p].url_adr, back[p].url_fil);
  1164.       back[p].r.is_write=0;
  1165.     }
  1166.         return 1;
  1167.     }
  1168.     return 0;
  1169. }
  1170.  
  1171. // effacer entrΘe
  1172. int back_delete(httrackp* opt, cache_back* cache, struct_back* sback, int p) {
  1173.   lien_back* const back = sback->lnk;
  1174.   const int back_max = sback->count;
  1175.   assertf(p >= 0 && p < back_max);
  1176.   if (p >= 0 && p < sback->count) {    // on sait jamais..
  1177.     // VΘrificateur d'intΘgritΘ
  1178. #if DEBUG_CHECKINT
  1179.     _CHECKINT(&back[p],"Appel back_delete")
  1180. #endif
  1181. #if HTS_DEBUG_CLOSESOCK
  1182.       DEBUG_W("back_delete: #%d\n" _ (int) p);
  1183. #endif
  1184.  
  1185.     // Finalize
  1186.     if (!back[p].finalized) {
  1187.       if (
  1188.         (back[p].status == STATUS_READY)      // ready
  1189.         &&
  1190.         (!back[p].testmode)        // not test mode
  1191.         &&
  1192.         (back[p].r.statuscode>0)   // not internal error
  1193.         ) {
  1194.           if (opt != NULL && opt->debug>1 && opt->log!=NULL) {
  1195.             HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"File '%s%s' -> %s not yet saved in cache - saving now"LF, back[p].url_adr, back[p].url_fil, back[p].url_sav); test_flush;
  1196.           }
  1197.         }
  1198.         if (cache != NULL) {
  1199.           back_finalize(opt, cache, sback, p);
  1200.         }
  1201.     }
  1202.     back[p].finalized = 0;
  1203.  
  1204.         // flush output buffers
  1205.         (void) back_flush_output(opt, cache, sback, p);
  1206.  
  1207.         return back_clear_entry(&back[p]);
  1208.   }
  1209.   return 0;
  1210. }
  1211.  
  1212. /* ensure that the entry is not locked */
  1213. void back_index_unlock(struct_back* sback, int p) {
  1214.   lien_back* const back = sback->lnk;
  1215.   if (back[p].locked) {
  1216.     back[p].locked = 0;   /* not locked anymore */
  1217.   }
  1218. }
  1219.  
  1220. /* the entry is available again */
  1221. static void back_set_free(lien_back* back) {
  1222.   back->locked = 0;
  1223.   back->status = STATUS_FREE;
  1224. }
  1225.  
  1226. /* delete entry content (clear the entry), but don't unallocate the entry itself */
  1227. int back_clear_entry(lien_back* back) {
  1228.     if (back != NULL) {
  1229.     // LibΘrer tous les sockets, handles, buffers..
  1230.     if (back->r.soc!=INVALID_SOCKET) {
  1231. #if HTS_DEBUG_CLOSESOCK
  1232.       DEBUG_W("back_delete: deletehttp\n");
  1233. #endif
  1234.       deletehttp(&back->r);
  1235.       back->r.soc=INVALID_SOCKET;
  1236.     }
  1237.     
  1238.     if (back->r.adr!=NULL) {  // reste un bloc α dΘsallouer
  1239.       freet(back->r.adr);
  1240.       back->r.adr=NULL;
  1241.     }
  1242.     if (back->chunk_adr!=NULL) {  // reste un bloc α dΘsallouer
  1243.       freet(back->chunk_adr);
  1244.       back->chunk_adr=NULL;
  1245.       back->chunk_size=0;
  1246.       back->chunk_blocksize=0;
  1247.       back->is_chunk=0;
  1248.     }
  1249.  
  1250.         // only for security
  1251.         if (back->tmpfile && back->tmpfile[0] != '\0') {
  1252.             (void) unlink(back->tmpfile);
  1253.             back->tmpfile = NULL;
  1254.         }
  1255.  
  1256.     // headers
  1257.     if (back->r.headers != NULL) {
  1258.       freet(back->r.headers);
  1259.       back->r.headers = NULL;
  1260.     }
  1261.  
  1262.     // Tout nettoyer
  1263.     memset(back, 0, sizeof(lien_back));  
  1264.     back->r.soc = INVALID_SOCKET;
  1265.         back->r.location = back->location_buffer;
  1266.     
  1267.     // Le plus important: libΘrer le champ
  1268.     back_set_free(back);
  1269.  
  1270.       return 1;
  1271.   }
  1272.   return 0;
  1273. }
  1274.  
  1275. /* Space left on backing stack */
  1276. int back_stack_available(struct_back* sback) {
  1277.   lien_back* const back = sback->lnk;
  1278.   const int back_max = sback->count;
  1279.   int p=0,n=0;
  1280.   for( ; p < back_max ; p++ )
  1281.     if ( back[p].status == STATUS_FREE )
  1282.       n++;
  1283.   return n;
  1284. }
  1285.  
  1286. // ajouter un lien en backing
  1287. int back_add_if_not_exists(struct_back* sback,httrackp* opt,cache_back* cache,char* adr,char* fil,char* save,char* referer_adr,char* referer_fil,int test) {
  1288.   back_clean(opt, cache, sback);  /* first cleanup the backlog to ensure that we have some entry left */
  1289.   if (!back_exist(sback,opt,adr,fil,save)) {
  1290.     return back_add(sback, opt, cache, adr, fil, save, referer_adr, referer_fil, test);
  1291.     }
  1292.   return 0;
  1293. }
  1294.  
  1295. int back_add(struct_back* sback,httrackp* opt,cache_back* cache,char* adr,char* fil,char* save,char* referer_adr,char* referer_fil,int test) {
  1296.   lien_back* const back = sback->lnk;
  1297.   const int back_max = sback->count;
  1298.   int p=0;
  1299.     char catbuff[CATBUFF_SIZE];
  1300.     char catbuff2[CATBUFF_SIZE];
  1301.   lien_back* itemback = NULL;
  1302.  
  1303. #if (defined(_DEBUG) || defined(DEBUG))
  1304.   if (!test && back_exist(sback,opt,adr,fil,save)) {
  1305.     int already_there = 0;
  1306.     if (opt->log!=NULL) {
  1307.       HTS_LOG(opt,LOG_ERROR); fprintf(opt->log,"error: back_add(%s,%s,%s) duplicate"LF, adr, fil, save);
  1308.     }
  1309.   }
  1310. #endif
  1311.  
  1312.   // vΘrifier cohΘrence de adr et fil (non vide!)
  1313.   if (strnotempty(adr)==0) {
  1314.     if (opt->log!=NULL) {
  1315.             HTS_LOG(opt,LOG_WARNING); fprintf(opt->log,"error: adr is empty for back_add"LF);
  1316.     }
  1317.     return -1;    // erreur!
  1318.   }
  1319.   if (strnotempty(fil)==0) {
  1320.     if (opt->log!=NULL) {
  1321.       HTS_LOG(opt,LOG_WARNING); fprintf(opt->log,"error: fil is empty for back_add"LF);
  1322.     }
  1323.     return -1;    // erreur!
  1324.   }
  1325.   // FIN vΘrifier cohΘrence de adr et fil (non vide!)
  1326.  
  1327.   // stats
  1328.   opt->state.back_add_stats++;
  1329.  
  1330.   // rechercher emplacement
  1331.   back_clean(opt, cache, sback);
  1332.   if ( ( p = back_search(opt, sback) ) >= 0) {
  1333.     back[p].send_too[0]='\0';  // Θventuels paramΦtres supplΘmentaires α transmettre au serveur
  1334.  
  1335.     // clear r
  1336.     if (back[p].r.soc!=INVALID_SOCKET) {  /* we never know */
  1337.       deletehttp(&back[p].r);
  1338.     }
  1339.     memset(&(back[p].r), 0, sizeof(htsblk)); 
  1340.     back[p].r.soc=INVALID_SOCKET; 
  1341.     back[p].r.location=back[p].location_buffer;
  1342.  
  1343.     // crΘer entrΘe
  1344.     strcpybuff(back[p].url_adr,adr);
  1345.     strcpybuff(back[p].url_fil,fil);
  1346.     strcpybuff(back[p].url_sav,save);
  1347.     //back[p].links_index = links_index;
  1348.     // copier referer si besoin
  1349.     strcpybuff(back[p].referer_adr,"");
  1350.     strcpybuff(back[p].referer_fil,"");
  1351.     if ((referer_adr) && (referer_fil)) {       // existe
  1352.       if ((strnotempty(referer_adr)) && (strnotempty(referer_fil))) {   // non vide
  1353.         if (referer_adr[0]!='!') {    // non dΘtruit
  1354.           if (strcmp(referer_adr,"file://")) {      // PAS file://
  1355.             if (strcmp(referer_adr,"primary")) {      // pas referer 1er lien
  1356.               strcpybuff(back[p].referer_adr,referer_adr);
  1357.               strcpybuff(back[p].referer_fil,referer_fil);
  1358.             }
  1359.           }
  1360.         }
  1361.       }
  1362.     }
  1363.     // sav ne sert α rien pour le moment
  1364.     back[p].r.size=0;                   // rien n'a encore ΘtΘ chargΘ
  1365.     back[p].r.adr=NULL;                 // pas de bloc de mΘmoire
  1366.     back[p].r.is_write=0;               // α priori stockage en mΘmoire
  1367.     back[p].maxfile_html=opt->maxfile_html;
  1368.     back[p].maxfile_nonhtml=opt->maxfile_nonhtml;
  1369.     back[p].testmode=test;              // mode test?
  1370.     if (!opt->http10)                 // option "forcer 1.0" dΘsactivΘe
  1371.       back[p].http11=1;               // autoriser http/1.1
  1372.     back[p].head_request=0;
  1373.     if (strcmp(back[p].url_sav,BACK_ADD_TEST)==0)    // HEAD
  1374.       back[p].head_request=1;
  1375.     else if (strcmp(back[p].url_sav,BACK_ADD_TEST2)==0)    // test en GET
  1376.       back[p].head_request=2;       // test en get
  1377.  
  1378.     /* Stop requested - abort backing */
  1379.     if (opt->state.stop) {
  1380.       back[p].r.statuscode=STATUSCODE_INVALID;        // fatal
  1381.       strcpybuff(back[p].r.msg,"mirror stopped by user");
  1382.       back[p].status=STATUS_READY;  // terminΘ
  1383.       back_set_finished(sback, p);
  1384.       if ((opt->debug>0) && (opt->log!=NULL)) {
  1385.         HTS_LOG(opt,LOG_WARNING); fprintf(opt->log,"File not added due to mirror cancel: %s%s"LF,adr,fil); test_flush;
  1386.       }            
  1387.       return 0;
  1388.     }
  1389.  
  1390.     // test "fast header" cache ; that is, tests we did that lead to 3XX/4XX/5XX response codes
  1391.     if (cache->cached_tests != NULL) {
  1392.       intptr_t ptr = 0;
  1393.       if (inthash_read(cache->cached_tests, concat(OPT_GET_BUFF(opt), adr, fil), &ptr)) {    // gotcha
  1394.         if (ptr != 0) {
  1395.           char* text = (char*) ptr;
  1396.           char* lf = strchr(text, '\n');
  1397.           int code = 0;
  1398.           if (sscanf(text, "%d", &code) == 1) {     // got code
  1399.              back[p].r.statuscode=code;
  1400.              back[p].status=STATUS_READY;  // terminΘ
  1401.              if (lf != NULL && *lf != '\0') {     // got location ?
  1402.                strcpybuff(back[p].r.location, lf + 1);
  1403.              }
  1404.              return 0;
  1405.           }
  1406.         }
  1407.       }
  1408.     }
  1409.  
  1410.     // tester cache
  1411.     if ((strcmp(adr,"file://"))           /* pas fichier */
  1412.       && ( (!test) || (cache->type==1) )   /* cache prioritaire, laisser passer en test! */
  1413.       && ( (strnotempty(save)) || (strcmp(fil,"/robots.txt")==0) ) ) {  // si en test on ne doit pas utiliser le cache sinon telescopage avec le 302..
  1414. #if HTS_FAST_CACHE
  1415.       intptr_t hash_pos;
  1416.       int hash_pos_return=0;
  1417. #else
  1418.       char* a=NULL;
  1419. #endif
  1420. #if HTS_FAST_CACHE
  1421.       if (cache->hashtable) { 
  1422. #else
  1423.       if (cache->use) { 
  1424. #endif
  1425.         char BIGSTK buff[HTS_URLMAXSIZE*4];
  1426. #if HTS_FAST_CACHE
  1427.         strcpybuff(buff,adr); strcatbuff(buff,fil);
  1428.         hash_pos_return=inthash_read(cache->hashtable,buff,&hash_pos);
  1429. #else
  1430.         buff[0]='\0'; strcatbuff(buff,"\n"); strcatbuff(buff,adr); strcatbuff(buff,"\n"); strcatbuff(buff,fil); strcatbuff(buff,"\n");
  1431.         a=strstr(cache->use,buff);
  1432. #endif
  1433.         
  1434.         // Ok, notΘ en cache->. mais bien prΘsent dans le cache ou sur disque?
  1435. #if HTS_FAST_CACHE
  1436.         if (hash_pos_return) {
  1437. #else
  1438.         if (a) {
  1439. #endif
  1440.           if (!test) {      // non mode test
  1441. #if HTS_FAST_CACHE
  1442.             uintptr_t pos=hash_pos;
  1443. #else
  1444.             int pos=-1;
  1445.             a+=strlen(buff);
  1446.             sscanf(a,"%d",&pos);    // lire position
  1447. #endif
  1448.  
  1449. #if HTS_FAST_CACHE==0
  1450.             if (pos<0) {    // pas de mise en cache data, vΘrifier existence
  1451. #endif
  1452.               /* note: no check with IS_DELAYED_EXT() enabled - postcheck by client please! */
  1453.               if (save[0] != '\0' && !IS_DELAYED_EXT(save) && fsize(fconv(catbuff,save)) <= 0) {  // fichier final n'existe pas ou est vide!
  1454.                 int found=0;
  1455.  
  1456.                 /* It is possible that the file has been moved due to changes in build structure */
  1457.                 {
  1458.                   char BIGSTK previous_save[HTS_URLMAXSIZE*2];
  1459.                   htsblk r;
  1460.                   previous_save[0] = '\0';
  1461.                   r = cache_readex(opt, cache, adr, fil, /*head*/NULL, /*bound to back[p] (temporary)*/back[p].location_buffer, previous_save, /*ro*/1);
  1462.                   /* Is supposed to be on disk only */
  1463.                   if (r.is_write && previous_save[0] != '\0') {
  1464.                     /* Exists, but with another (old) filename: rename (almost) silently */
  1465.                     if (strcmp(previous_save, save) != 0 && fexist(fconv(catbuff, previous_save))) {
  1466.                       rename(fconv(catbuff, previous_save), fconv(catbuff2,save));
  1467.                       if (fexist(fconv(catbuff,save))) {
  1468.                         found = 1;
  1469.                         if ((opt->debug>1) && (opt->log!=NULL)) {
  1470.                           HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"File '%s' has been renamed since last mirror to '%s' ; applying changes"LF, previous_save, save); test_flush;
  1471.                         }
  1472.                       } else {
  1473.                         if ((opt->debug>0) && (opt->log!=NULL)) {
  1474.                           HTS_LOG(opt,LOG_ERROR); fprintf(opt->log,"Could not rename '%s' to '%s' ; will have to retransfer it"LF, previous_save, save); test_flush;
  1475.                         }
  1476.                       }
  1477.                     }
  1478.                   }
  1479.                   back[p].location_buffer[0] = '\0';
  1480.                 }
  1481.                 
  1482.                 /* Not found ? */
  1483.                 if (!found) {
  1484. #if HTS_FAST_CACHE
  1485.                   hash_pos_return=0;
  1486. #else
  1487.                   a=NULL;    
  1488. #endif
  1489.                   // dΘvalider car non prΘsent sur disque dans structure originale!!!
  1490.                   // sinon, le fichier est ok α priori, mais on renverra un if-modified-since pour
  1491.                   // en Ωtre s√r
  1492.                   if (opt->norecatch) {              // tester norecatch
  1493.                     if (!fexist(fconv(catbuff,save))) {  // fichier existe pas mais dΘclarΘ: on l'a effacΘ
  1494.                       FILE* fp=fopen(fconv(catbuff,save),"wb");
  1495.                       if (fp) fclose(fp);
  1496.                       if (opt->log!=NULL) {
  1497.                         HTS_LOG(opt,LOG_WARNING); fprintf(opt->log,"Previous file not found (erased by user ?), ignoring: %s%s"LF,back[p].url_adr,back[p].url_fil); test_flush;
  1498.                       }
  1499.                     }
  1500.                   } else {
  1501.                     if (opt->log!=NULL) {
  1502.                       HTS_LOG(opt,LOG_WARNING); fprintf(opt->log,"Previous file not found (erased by user ?), recatching: %s%s"LF,back[p].url_adr,back[p].url_fil); test_flush;
  1503.                     }
  1504.                   }
  1505.                 }
  1506.               }  // fsize() <= 0
  1507. #if HTS_FAST_CACHE==0
  1508.             }
  1509. #endif
  1510.           }
  1511.         }
  1512.         //
  1513.       } else {
  1514. #if HTS_FAST_CACHE
  1515.         hash_pos_return=0;
  1516. #else
  1517.         a=NULL;
  1518. #endif
  1519.       }
  1520.  
  1521.       // Existe pas en cache, ou bien pas de cache prΘsent
  1522. #if HTS_FAST_CACHE
  1523.       if (hash_pos_return) {  // OK existe en cache (et donnΘes aussi)!
  1524. #else
  1525.       if (a!=NULL) {  // OK existe en cache (et donnΘes aussi)!
  1526. #endif
  1527.         if (cache->type==1) {   // cache prioritaire (pas de test if-modified..)
  1528.                                // dans ce cas on peut Θgalement lire des rΘponses cachΘes comme 404,302...
  1529.           // lire dans le cache
  1530.           if (!test)
  1531.             back[p].r = cache_read(opt,cache,adr,fil,save, back[p].location_buffer);
  1532.           else
  1533.             back[p].r = cache_read(opt,cache,adr,fil,NULL, back[p].location_buffer);  // charger en tΩte uniquement du cache
  1534.  
  1535.           /* ensure correct location buffer set */
  1536.           back[p].r.location=back[p].location_buffer;
  1537.  
  1538.           /* Interdiction taille par le wizard? --> dΘtruire */
  1539.           if (back[p].r.statuscode != -1) {  // pas d'erreur de lecture
  1540.             if (!back_checksize(opt,&back[p],0)) {
  1541.               back[p].status=STATUS_READY;  // FINI
  1542.               back_set_finished(sback, p);
  1543.               back[p].r.statuscode=STATUSCODE_TOO_BIG;
  1544.               if (!back[p].testmode)
  1545.                 strcpybuff(back[p].r.msg,"Cached file skipped (too big)");
  1546.               else
  1547.                 strcpybuff(back[p].r.msg,"Test: Cached file skipped  (too big)");
  1548.               return 0;
  1549.             }
  1550.           }
  1551.  
  1552.           if (back[p].r.statuscode != -1 || IS_DELAYED_EXT(save)) {  // pas d'erreur de lecture ou test retardΘ
  1553.             if ((opt->debug>0) && (opt->log!=NULL)) {
  1554.               if (!test) {
  1555.                 HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"File immediately loaded from cache: %s%s"LF,back[p].url_adr,back[p].url_fil); test_flush;
  1556.               } else {
  1557.                 HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"File immediately tested from cache: %s%s"LF,back[p].url_adr,back[p].url_fil); test_flush;
  1558.               }
  1559.             }
  1560.             back[p].r.notmodified=1;    // fichier non modifiΘ
  1561.             back[p].status=STATUS_READY;  // OK prΩt
  1562.             //file_notify(back[p].url_adr, back[p].url_fil, back[p].url_sav, 0, 0, back[p].r.notmodified);        // not modified
  1563.             back_set_finished(sback, p);
  1564.  
  1565.             // finalize transfer
  1566.             if (!test) {
  1567.               if (back[p].r.statuscode>0) {
  1568.                 back_finalize(opt,cache,sback,p);
  1569.               }
  1570.             }
  1571.  
  1572.             return 0;
  1573.           } else {  // erreur
  1574.             // effacer r
  1575.             memset(&(back[p].r), 0, sizeof(htsblk)); back[p].r.soc=INVALID_SOCKET; back[p].r.location=back[p].location_buffer;
  1576.             // et continuer (chercher le fichier)
  1577.           }
  1578.           
  1579.         } else if (cache->type==2) {    // si en cache, demander de tester If-Modified-Since
  1580.           htsblk r;
  1581.           cache_header(opt,cache,adr,fil,&r);
  1582.  
  1583.           /* Interdiction taille par le wizard? */
  1584.           {
  1585.             LLint save_totalsize=back[p].r.totalsize;
  1586.             back[p].r.totalsize=r.totalsize;
  1587.             if (!back_checksize(opt,&back[p],1)) {
  1588.               r.statuscode = STATUSCODE_INVALID;
  1589.               //
  1590.               back[p].status=STATUS_READY;  // FINI
  1591.               back_set_finished(sback, p);
  1592.               back[p].r.statuscode=STATUSCODE_TOO_BIG;
  1593.               deletehttp(&back[p].r); back[p].r.soc=INVALID_SOCKET;
  1594.               if (!back[p].testmode)
  1595.                 strcpybuff(back[p].r.msg,"File too big");
  1596.               else
  1597.                 strcpybuff(back[p].r.msg,"Test: File too big");
  1598.               return 0;
  1599.             }
  1600.             back[p].r.totalsize=save_totalsize;
  1601.           }
  1602.           
  1603.           if (r.statuscode != -1) {
  1604.             if (r.statuscode==HTTP_OK) {     // uniquement des 200 (OK)
  1605.               if (strnotempty(r.etag)) {  // ETag (RFC2616)
  1606.                 /*
  1607.                 - If both an entity tag and a Last-Modified value have been
  1608.                 provided by the origin server, SHOULD use both validators in
  1609.                 cache-conditional requests. This allows both HTTP/1.0 and
  1610.                 HTTP/1.1 caches to respond appropriately.
  1611.                 */
  1612.                 if (strnotempty(r.lastmodified))
  1613.                   sprintf(back[p].send_too,"If-None-Match: %s\r\nIf-Modified-Since: %s\r\n",r.etag,r.lastmodified);
  1614.                 else
  1615.                   sprintf(back[p].send_too,"If-None-Match: %s\r\n",r.etag);
  1616.               }
  1617.               else if (strnotempty(r.lastmodified))
  1618.                 sprintf(back[p].send_too,"If-Modified-Since: %s\r\n",r.lastmodified);
  1619.               else if (strnotempty(cache->lastmodified))
  1620.                 sprintf(back[p].send_too,"If-Modified-Since: %s\r\n",cache->lastmodified);
  1621.               
  1622.               /* this is an update of a file */
  1623.               if (strnotempty(back[p].send_too))
  1624.                 back[p].is_update=1;
  1625.               back[p].r.req.nocompression=1;   /* Do not compress when updating! */
  1626.               
  1627.             }
  1628.           }
  1629. #if DEBUGCA
  1630.           printf("..is modified test %s\n",back[p].send_too);
  1631. #endif
  1632.         } 
  1633.       } 
  1634.       /* Not in cache ; maybe in temporary cache ? Warning: non-movable "url_sav" */
  1635.       else if (back_unserialize_ref(opt, adr, fil, &itemback) == 0) {
  1636.         const long file_size = fsize(itemback->url_sav);
  1637.         /* Found file on disk */
  1638.         if (file_size > 0) {
  1639.           char *send_too = back[p].send_too;
  1640.           sprintf(send_too, "Range: bytes="LLintP"-\r\n", (LLint) file_size);
  1641.           send_too += strlen(send_too);
  1642.           /* add etag information */
  1643.           if (strnotempty(itemback->r.etag)) {
  1644.             sprintf(send_too,"If-Match: %s\r\n", itemback->r.etag);
  1645.             send_too += strlen(send_too);
  1646.           }
  1647.           /* add date information */
  1648.           if (strnotempty(itemback->r.lastmodified)) {
  1649.             sprintf(send_too,"If-Unmodified-Since: %s\r\n", itemback->r.lastmodified);
  1650.             send_too += strlen(send_too);
  1651.           }
  1652.           back[p].http11=1;                /* 1.1 */
  1653.           back[p].range_req_size=(LLint) file_size;
  1654.           back[p].r.req.range_used=1;
  1655.           back[p].is_update=1;             /* this is an update of a file */
  1656.           back[p].r.req.nocompression=1;   /* Do not compress when updating! */
  1657.         } else {
  1658.           /* broken ; remove */
  1659.           url_savename_refname_remove(opt, adr, fil);
  1660.         }
  1661.         /* cleanup */
  1662.         back_clear_entry(itemback);                /* delete entry content */
  1663.         freet(itemback);                                    /* delete item */
  1664.         itemback = NULL;
  1665.       }
  1666.       /* Not in cache or temporary cache ; found on disk ? (hack) */
  1667.       else if (fexist(save)) {
  1668.         off_t sz=fsize(save);
  1669.         // Bon, lα il est possible que le fichier ait ΘtΘ partiellement transfΘrΘ
  1670.         // (s'il l'avait ΘtΘ en totalitΘ il aurait ΘtΘ inscrit dans le cache ET existerait sur disque)
  1671.         // PAS de If-Modified-Since, on a pas connaissance des donnΘes α la date du cache
  1672.         // On demande juste les donnΘes restantes si le date est valide (206), tout sinon (200)
  1673.         if ((ishtml(opt,save) != 1) && (ishtml(opt,back[p].url_fil)!=1)) {   // NON HTML (liens changΘs!!)
  1674.           if (sz>0) {    // Fichier non vide? (question bΩte, sinon on transfert tout!)
  1675.             char lastmodified[256];
  1676.             get_filetime_rfc822(save, lastmodified);
  1677.             if (strnotempty(lastmodified)) {     /* pas de If-.. possible */
  1678. #if DEBUGCA
  1679.               printf("..if unmodified since %s size "LLintP"\n", lastmodified, (LLint)sz);
  1680. #endif
  1681.               if ((opt->debug>1) && (opt->log!=NULL)) {
  1682.                 HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"File partially present ("LLintP" bytes): %s%s"LF,(LLint)sz,back[p].url_adr,back[p].url_fil); test_flush;
  1683.               }
  1684.  
  1685.               /* impossible - don't have etag or date
  1686.               if (strnotempty(back[p].r.etag)) {  // ETag (RFC2616)
  1687.               sprintf(back[p].send_too,"If-None-Match: %s\r\n",back[p].r.etag);
  1688.               back[p].http11=1;    // En tΩte 1.1
  1689.               } else if (strnotempty(back[p].r.lastmodified)) {
  1690.               sprintf(back[p].send_too,"If-Unmodified-Since: %s\r\n",back[p].r.lastmodified);
  1691.               back[p].http11=1;    // En tΩte 1.1
  1692.               } else 
  1693.               */
  1694.               if (strlen(lastmodified)) {
  1695.                 sprintf(back[p].send_too,
  1696.                   "If-Unmodified-Since: %s\r\nRange: bytes="LLintP"-\r\n"
  1697.                   , lastmodified, (LLint)sz);
  1698.                 back[p].http11=1;    // En tΩte 1.1
  1699.                 back[p].is_update=1;             /* this is an update of a file */
  1700.                 back[p].range_req_size=sz;
  1701.                 back[p].r.req.range_used=1;
  1702.                 back[p].r.req.nocompression=1;
  1703.               } else {
  1704.                 if ((opt->debug>0) && (opt->log!=NULL)) {
  1705.                   HTS_LOG(opt,LOG_WARNING); fprintf(opt->log,"Could not find timestamp for partially present file, restarting (lost "LLintP" bytes): %s%s"LF,(LLint)sz,back[p].url_adr,back[p].url_fil); test_flush;
  1706.                 }
  1707.               }
  1708.  
  1709.             } else { 
  1710.               if ((opt->debug>0) && (opt->log!=NULL)) {
  1711.                 HTS_LOG(opt,LOG_WARNING);
  1712.                 /*
  1713.                 if (opt->http10)
  1714.                 fprintf(opt->log,"File partially present (%d bytes) retransfered due to HTTP/1.0 settings: %s%s"LF,sz,back[p].url_adr,back[p].url_fil);
  1715.                 else
  1716.                 */
  1717.                 fprintf(opt->log,"File partially present ("LLintP" bytes) retransfered due to lack of cache: %s%s"LF,(LLint)sz,back[p].url_adr,back[p].url_fil); 
  1718.                 test_flush;
  1719.               }
  1720.               /* Sinon requΩte normale... */
  1721.               back[p].http11=0;
  1722.             }
  1723.           } else if (opt->norecatch) {              // tester norecatch
  1724.             filenote(&opt->state.strc,save,NULL);       // ne pas purger tout de mΩme
  1725.             file_notify(opt,back[p].url_adr, back[p].url_fil, back[p].url_sav, 0, 0, back[p].r.notmodified);
  1726.             back[p].status=STATUS_READY;  // OK prΩt
  1727.             back_set_finished(sback, p);
  1728.             back[p].r.statuscode=STATUSCODE_INVALID;  // erreur
  1729.             strcpybuff(back[p].r.msg,"Null-size file not recaught");
  1730.             return 0;
  1731.           }
  1732.         } else {
  1733.           if ((opt->debug>0) && (opt->log!=NULL)) {
  1734.             HTS_LOG(opt,LOG_WARNING);
  1735.             fprintf(opt->log,"HTML file ("LLintP" bytes) retransfered due to lack of cache: %s%s"LF,(LLint)sz,back[p].url_adr,back[p].url_fil); 
  1736.             test_flush;
  1737.           }
  1738.           /* Sinon requΩte normale... */
  1739.           back[p].http11=0;
  1740.         }
  1741.       }
  1742.     }
  1743.  
  1744.  
  1745.     {
  1746.       ///htsblk r;   non directement dans la structure-rΘponse!
  1747.       T_SOC soc;
  1748.       
  1749.       // ouvrir liaison, envoyer requΦte
  1750.       // ne pas traiter ou recevoir l'en tΩte immΘdiatement
  1751.       memset(&(back[p].r), 0, sizeof(htsblk)); back[p].r.soc=INVALID_SOCKET; back[p].r.location=back[p].location_buffer;
  1752.       // recopier proxy
  1753.       if ((back[p].r.req.proxy.active = opt->proxy.active)) {
  1754.         if (StringBuff(opt->proxy.bindhost) != NULL)
  1755.           strcpybuff(back[p].r.req.proxy.bindhost, StringBuff(opt->proxy.bindhost));
  1756.         if (StringBuff(opt->proxy.name) != NULL)
  1757.           strcpybuff(back[p].r.req.proxy.name, StringBuff(opt->proxy.name));
  1758.         back[p].r.req.proxy.port = opt->proxy.port;
  1759.       }
  1760.       // et user-agent
  1761.       strcpy(back[p].r.req.user_agent,StringBuff(opt->user_agent));
  1762.       strcpy(back[p].r.req.referer,StringBuff(opt->referer));
  1763.       strcpy(back[p].r.req.from,StringBuff(opt->from));
  1764.       strcpy(back[p].r.req.lang_iso,StringBuff(opt->lang_iso));
  1765.       back[p].r.req.user_agent_send=opt->user_agent_send;
  1766.       // et http11
  1767.       back[p].r.req.http11=back[p].http11;
  1768.       back[p].r.req.nocompression=opt->nocompression;
  1769.       back[p].r.req.nokeepalive=opt->nokeepalive;
  1770.  
  1771.       // mode ftp, court-circuit!
  1772.       if (strfield(back[p].url_adr,"ftp://")) {
  1773.         if (back[p].testmode) {
  1774.                 if (opt->log!=NULL) {
  1775.             HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"error: forbidden test with ftp link for back_add"LF);
  1776.           }
  1777.           return -1;    // erreur pas de test permis
  1778.         }
  1779.         if (!(back[p].r.req.proxy.active && opt->ftp_proxy)) { // connexion directe, gΘrΘe en thread
  1780.                     FTPDownloadStruct *str = (FTPDownloadStruct*) malloc(sizeof(FTPDownloadStruct));
  1781.                     str->pBack = &back[p];
  1782.                     str->pOpt = opt;
  1783.                     /* */
  1784.           back[p].status=STATUS_FTP_TRANSFER;   // connexion ftp
  1785. #if USE_BEGINTHREAD
  1786.                     launch_ftp(str);
  1787. #else
  1788. #error Must have pthreads
  1789. #endif
  1790.           return 0;
  1791.         }
  1792.       }
  1793. #if HTS_USEMMS
  1794.       else if (strfield(back[p].url_adr,"mms://")) {
  1795.                 MMSDownloadStruct str;
  1796.         if (back[p].testmode) {
  1797.                 if (opt->log!=NULL) {
  1798.             HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"error: forbidden test with mms link for back_add"LF);
  1799.           }
  1800.           return -1;    // erreur pas de test permis
  1801.         }
  1802.         if (back[p].r.req.proxy.active) {
  1803.           HTS_LOG(opt,LOG_WARNING); fprintf(opt->log,"warning: direct connection for mms links (proxy settings ignored)"LF);
  1804.                 }
  1805.                 back[p].status=STATUS_FTP_TRANSFER;   // connexion externe
  1806.                 str.pBack = &back[p];
  1807.                 str.pOpt = opt;
  1808.                 launch_mms(&str);
  1809.                 return 0;
  1810.       }
  1811. #endif
  1812. #if HTS_USEOPENSSL
  1813.       else if (SSL_is_available && strfield(back[p].url_adr,"https://")) {        // let's rock
  1814.         back[p].r.ssl = 1;
  1815.         // back[p].r.ssl_soc = NULL;
  1816.         back[p].r.ssl_con = NULL;
  1817.       }
  1818. #endif
  1819.       
  1820.       if (!back_trylive(opt, cache, sback, p)) {
  1821. #if HTS_XGETHOST
  1822. #if HDEBUG
  1823.         printf("back_solve..\n");
  1824. #endif
  1825.         back[p].status=STATUS_WAIT_DNS;    // tentative de rΘsolution du nom de host
  1826.         soc=INVALID_SOCKET;    // pas encore ouverte
  1827.         back_solve(opt, &back[p]);  // prΘparer
  1828.         if (host_wait(opt, &back[p])) {  // prΩt, par ex fichier ou dispo dans dns
  1829. #if HDEBUG
  1830.           printf("ok, dns cache ready..\n");
  1831. #endif
  1832.           soc=http_xfopen(opt,0,0,0,back[p].send_too,adr,fil,&(back[p].r));
  1833.           if (soc==INVALID_SOCKET) {
  1834.             back[p].status=STATUS_READY;  // fini, erreur
  1835.             back_set_finished(sback, p);
  1836.           }
  1837.         }
  1838.         //
  1839. #else
  1840.         //
  1841. #if CNXDEBUG
  1842.         printf("XFopen..\n");
  1843. #endif
  1844.         
  1845.         if (strnotempty(back[p].send_too))    // envoyer un if-modified-since
  1846. #if HTS_XCONN
  1847.           soc=http_xfopen(0,0,0,back[p].send_too,adr,fil,&(back[p].r));
  1848. #else
  1849.         soc=http_xfopen(0,0,1,back[p].send_too,adr,fil,&(back[p].r));
  1850. #endif
  1851.         else
  1852. #if HTS_XCONN
  1853.           soc=http_xfopen(test,0,0,NULL,adr,fil,&(back[p].r));
  1854. #else
  1855.         soc=http_xfopen(test,0,1,NULL,adr,fil,&(back[p].r));
  1856. #endif
  1857. #endif
  1858.       } else {
  1859.         soc = back[p].r.soc;
  1860.  
  1861.         if ((opt->debug>1) && (opt->log!=NULL)) {
  1862.           HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"(Keep-Alive): successfully linked #%d (for %s%s)"LF, 
  1863.             back[p].r.debugid,
  1864.             back[p].url_adr, back[p].url_fil); test_flush;
  1865.         }
  1866.       }
  1867.       
  1868.       if (opt->timeout>0) {    // gestion du opt->timeout
  1869.         back[p].timeout=opt->timeout;
  1870.         back[p].timeout_refresh=time_local();
  1871.       } else {
  1872.         back[p].timeout=-1;    // pas de gestion (default)
  1873.       }
  1874.       
  1875.       if (opt->rateout>0) {    // gestion d'un taux minimum de transfert tolΘrΘ
  1876.         back[p].rateout=opt->rateout;
  1877.         back[p].rateout_time=time_local();
  1878.       } else {
  1879.         back[p].rateout=-1;    // pas de gestion (default)
  1880.       }
  1881.  
  1882.       // Note: on charge les code-page erreurs (erreur 404, etc) dans le cas o∙ cela est
  1883.       // rattrapable (exemple: 301,302 moved xxx -> refresh sur la page!)
  1884.       //if ((back[p].statuscode!=HTTP_OK) || (soc<0)) { // ERREUR HTTP/autre
  1885.  
  1886. #if CNXDEBUG
  1887. printf("Xfopen ok, poll..\n");
  1888. #endif
  1889.  
  1890. #if HTS_XGETHOST
  1891.     if (soc!=INVALID_SOCKET)
  1892.       if (back[p].status==STATUS_WAIT_DNS) {  // pas d'erreur
  1893.         if (!back[p].r.is_file)
  1894.           back[p].status=STATUS_CONNECTING;   // connexion en cours
  1895.         else
  1896.           back[p].status=1;     // fichier
  1897.       }
  1898.  
  1899. #else
  1900.       if (soc==INVALID_SOCKET) { // erreur socket
  1901.         back[p].status=STATUS_READY;    // FINI
  1902.         back_set_finished(sback, p);
  1903.         //if (back[p].soc!=INVALID_SOCKET) deletehttp(back[p].soc);
  1904.         back[p].r.soc=INVALID_SOCKET;
  1905.       } else {
  1906.         if (!back[p].r.is_file)
  1907. #if HTS_XCONN
  1908.           back[p].status=STATUS_CONNECTING;   // connexion en cours
  1909. #else
  1910.           back[p].status=99;    // chargement en tΩte en cours
  1911. #endif
  1912.         else
  1913.           back[p].status=1;     // chargement fichier
  1914. #if BDEBUG==1
  1915.         printf("..loading header\n");
  1916. #endif
  1917.       }
  1918. #endif
  1919.       
  1920.     }
  1921.  
  1922.  
  1923.     // note: si il y a erreur (404,etc) status=2 (terminΘ/Θchec) mais
  1924.     // le lien est considΘrΘ comme traitΘ
  1925.     //if (back[p].soc<0)  // erreur
  1926.     //  return -1;
  1927.  
  1928.     return 0;
  1929.   } else {
  1930.     if (opt->log!=NULL) {
  1931.       HTS_LOG(opt,LOG_WARNING); fprintf(opt->log,"error: no space left in stack for back_add"LF);
  1932.       if ( ( opt->state.debug_state & 1 ) == 0 ) {    /* debug_state<0> == debug 'no space left in stack' */
  1933.         int i;
  1934.         HTS_LOG(opt,LOG_WARNING); fprintf(opt->log,"debug: DUMPING %d BLOCKS"LF, back_max);
  1935.         opt->state.debug_state |= 1;    /* once */
  1936.         /* OUTPUT FULL DEBUG INFORMATION THE FIRST TIME WE SEE THIS VERY ANNOYING BUG,
  1937.         HOPING THAT SOME USER REPORT WILL QUICKLY SOLVE THIS PROBLEM :p */
  1938.         for(i = 0 ; i < back_max ; i++ ) {
  1939.           if (back[i].status != -1) {
  1940.             int may_clean = slot_can_be_cleaned(&back[i]);
  1941.             int may_finalize = may_clean && slot_can_be_finalized(opt, &back[i]);
  1942.             int may_serialize = slot_can_be_cached_on_disk(&back[i]);
  1943.             HTS_LOG(opt,LOG_INFO);
  1944.             fprintf(opt->log,
  1945.               "debug: back[%03d]: may_clean=%d, may_finalize_disk=%d, may_serialize=%d:"LF
  1946.               "\t" "finalized(%d), status(%d), locked(%d), delayed(%d), test(%d), "LF
  1947.               "\t" "statuscode(%d), size(%d), is_write(%d), may_hypertext(%d), "LF
  1948.               "\t" "contenttype(%s), url(%s%s), save(%s)"LF,
  1949.               i,
  1950.               may_clean, may_finalize, may_serialize,
  1951.               back[i].finalized,
  1952.               back[i].status,
  1953.               back[i].locked,
  1954.               IS_DELAYED_EXT(back[i].url_sav),
  1955.               back[i].testmode,
  1956.               back[i].r.statuscode,
  1957.               (int) back[i].r.size,
  1958.               back[i].r.is_write,
  1959.               may_be_hypertext_mime(opt,back[i].r.contenttype, back[i].url_fil),
  1960.               /* */
  1961.               back[i].r.contenttype,
  1962.               back[i].url_adr, back[i].url_fil,
  1963.               back[i].url_sav ? back[i].url_sav : "<null>"
  1964.               );
  1965.           }
  1966.         }
  1967.       }
  1968.  
  1969.     }
  1970.     return -1;    // plus de place
  1971.   }
  1972. }
  1973.  
  1974.  
  1975.  
  1976. #if HTS_XGETHOST
  1977. #if USE_BEGINTHREAD
  1978. // lancement multithread du robot
  1979. typedef struct {
  1980.     char iadr_p[HTS_URLMAXSIZE];
  1981.     httrackp *opt;
  1982. } HostlookupStruct;
  1983. void Hostlookup(void* pP) {
  1984.     HostlookupStruct *str = (HostlookupStruct*) pP;
  1985.   char iadr[256];
  1986.     t_dnscache* cache=_hts_cache(str->opt);  // adresse du cache
  1987.   t_hostent* hp;
  1988.   int error_found=0;
  1989.  
  1990.   // recopier (aprΦs id:pass)
  1991. #if DEBUGDNS 
  1992.   printf("resolv in background: %s\n",jump_identification(iadr_p));
  1993. #endif
  1994.   strcpybuff(iadr,jump_identification(str->iadr_p));
  1995.   // couper Θventuel :
  1996.   {
  1997.     char *a;
  1998.     if ( (a=jump_toport(iadr)) )
  1999.       *a='\0';          // get rid of it
  2000.   }
  2001.   freet(pP);
  2002.  
  2003.   hts_mutexlock(&dns_lock);
  2004.  
  2005.   while(cache->n) {
  2006.     if (strcmp(cache->iadr,iadr)==0) {
  2007.       error_found=1;
  2008.     }
  2009.     cache=cache->n;    // calculer queue
  2010.   }
  2011.   if (strcmp(cache->iadr,iadr)==0) {
  2012.     error_found=1;
  2013.   }
  2014.  
  2015.   if (!error_found) {
  2016.     // en gros copie de hts_gethostbyname sans le return
  2017.     cache->n=(t_dnscache*) calloct(1,sizeof(t_dnscache));
  2018.     if (cache->n!=NULL) {
  2019.       t_fullhostent fullhostent_buffer;
  2020.       strcpybuff(cache->n->iadr,iadr);
  2021.       cache->n->host_length=0;        /* pour le moment rien */
  2022.       cache->n->n=NULL;
  2023.       
  2024.       /* resolve */
  2025. #if DEBUGDNS 
  2026.       printf("gethostbyname() in progress for %s\n",iadr);
  2027. #endif
  2028.       cache->n->host_length=-1;
  2029.       memset(cache->n->host_addr, 0, sizeof(cache->n->host_addr));
  2030.       hp=vxgethostbyname(iadr, &fullhostent_buffer);
  2031.       if (hp!=NULL) {
  2032.         memcpy(cache->n->host_addr, hp->h_addr, hp->h_length);
  2033.         cache->n->host_length = hp->h_length;
  2034.       }
  2035.     }
  2036.   } else {
  2037. #if DEBUGDNS 
  2038.     printf("aborting resolv for %s (found)\n",iadr);
  2039. #endif
  2040.   }
  2041.  
  2042.   hts_mutexrelease(&dns_lock);
  2043.  
  2044. #if DEBUGDNS 
  2045.   printf("quitting resolv for %s (result: %d)\n",iadr,(cache->n!=NULL)?cache->n->host_length:(-999));
  2046. #endif
  2047. }
  2048. #endif
  2049.  
  2050. // attendre que le host (ou celui du proxy) ait ΘtΘ rΘsolu
  2051. // si c'est un fichier, la rΘsolution est immΘdiate
  2052. // idem pour ftp://
  2053. void back_solve(httrackp *opt, lien_back* back) {
  2054.   if ((!strfield(back->url_adr,"file://")) 
  2055.         && ! strfield(back->url_adr,"ftp://")
  2056. #if HTS_USEMMS
  2057.         && ! strfield(back->url_adr,"mms://")
  2058. #endif
  2059.         ) {
  2060.   //## if (back->url_adr[0]!=lOCAL_CHAR) {  // qq chose α prΘparer
  2061.     const char* a;
  2062.     if (!(back->r.req.proxy.active))
  2063.       a=back->url_adr;
  2064.     else
  2065.       a=back->r.req.proxy.name;
  2066.     a = jump_protocol(a);
  2067.     if (!hts_dnstest(opt, a)) {   // non encore testΘ!..
  2068.       // inscire en thread
  2069. #ifdef _WIN32
  2070.       // Windows
  2071. #if USE_BEGINTHREAD
  2072.       {
  2073.                 HostlookupStruct *str = (HostlookupStruct*)malloct(sizeof(HostlookupStruct));
  2074.         if (str) {
  2075.                     strcpybuff(str->iadr_p, a);
  2076.                     str->opt = opt;
  2077.           hts_newthread(Hostlookup, str);
  2078.         }
  2079.       }
  2080. #else
  2081.       /*t_hostent* h=*/
  2082.       /*hts_gethostbyname(a);*/  // calcul
  2083. #endif
  2084. #else
  2085. #if USE_BEGINTHREAD
  2086.         char* p = calloct(strlen(a)+2,1);
  2087.         if (p) {
  2088.           strcpybuff(p,a);
  2089.           hts_newthread( Hostlookup , p );
  2090.         }
  2091. #else
  2092.       // Sous Unix, le gethostbyname() est bloquant..
  2093.       /*t_hostent* h=*/
  2094.       /*hts_gethostbyname(a);*/  // calcul
  2095. #endif
  2096. #endif
  2097.     }
  2098.   }
  2099. }
  2100.  
  2101. // dΘtermine si le host a pu Ωtre rΘsolu
  2102. int host_wait(httrackp *opt, lien_back* back) {
  2103.   if ((!strfield(back->url_adr,"file://")) 
  2104.         && (!strfield(back->url_adr,"ftp://"))
  2105. #if HTS_USEMMS
  2106.         && (!strfield(back->url_adr,"mms://"))
  2107. #endif
  2108.         ) {
  2109.   //## if (back->url_adr[0]!=lOCAL_CHAR) {
  2110.     if (!(back->r.req.proxy.active)) {
  2111.       return (hts_dnstest(opt, back->url_adr));
  2112.     } else {
  2113.       return (hts_dnstest(opt, back->r.req.proxy.name));      
  2114.     }
  2115.   } else return 1;    // prΩt, fichier local
  2116. }
  2117. #endif
  2118.  
  2119.  
  2120. // Θlimine les fichiers non html en backing (anticipation)
  2121. // cleanup non-html files in backing to save backing space
  2122. // and allow faster "save in cache" operation
  2123. // also cleanup keep-alive sockets and ensure that not too many sockets are being opened
  2124.  
  2125. static int slot_can_be_cleaned(const lien_back* back) {
  2126.   return 
  2127.     (back->status == STATUS_READY)                        // ready
  2128.     /* Check autoclean */
  2129.     && (!back->testmode)                                  // not test mode
  2130.     && (strnotempty(back->url_sav))                       // filename exists
  2131.     && (HTTP_IS_OK(back->r.statuscode))                   // HTTP "OK"
  2132.     && (back->r.size > 0)                                 // size>0
  2133.     ;
  2134. }
  2135.  
  2136. static int slot_can_be_finalized(httrackp* opt, const lien_back* back) {
  2137.   return
  2138.     (back->r.is_write                             // not in memory (on disk, ready)
  2139.     && !is_hypertext_mime(opt,back->r.contenttype, back->url_fil)        // not HTML/hypertext
  2140.     && !may_be_hypertext_mime(opt,back->r.contenttype, back->url_fil)    // may NOT be parseable mime type
  2141.     );
  2142. }
  2143.  
  2144. void back_clean(httrackp* opt,cache_back* cache,struct_back* sback) {
  2145.   lien_back* const back = sback->lnk;
  2146.   const int back_max = sback->count;
  2147.   int oneMore = ( (opt->state._hts_in_html_parsing == 2 && opt->maxsoc >= 2) || (opt->state._hts_in_html_parsing == 1 && opt->maxsoc >= 4) ) ? 1 : 0;  // testing links
  2148.   int i;
  2149.   for(i=0;i<back_max;i++) {
  2150.     if (slot_can_be_cleaned(&back[i])) {
  2151.       if (slot_can_be_finalized(opt, &back[i])) {
  2152.         (void) back_flush_output(opt, cache, sback, i);        // flush output buffers
  2153.         usercommand(opt, 0, NULL, back[i].url_sav, back[i].url_adr, back[i].url_fil);
  2154.         //if (back[i].links_index >= 0) {
  2155.         //  assertf(back[i].links_index < opt->hash->max_lien);
  2156.         //  opt->hash->liens[back[i].links_index]->pass2 = -1;
  2157.         //  // *back[i].pass2_ptr=-1;  // Done!
  2158.         //}
  2159.         /* MANDATORY if we don't want back_fill() to endlessly put the same file on download! */
  2160.         {
  2161.           int index = hash_read(opt->hash,back[i].url_sav,"",0,opt->urlhack);      // lecture type 0 (sav)
  2162.           if (index >= 0) {
  2163.             opt->hash->liens[index]->pass2 = -1;      /* DONE! */
  2164.           } else {
  2165.             if (opt->log != NULL) {
  2166.               HTS_LOG(opt,LOG_INFO); fprintf(opt->log,"engine: warning: entry cleaned up, but no trace on heap: %s%s (%s)"LF,back[i].url_adr, back[i].url_fil,back[i].url_sav);
  2167.               test_flush;
  2168.             }
  2169.           }
  2170.         }
  2171.         HTS_STAT.stat_background++;
  2172.         if ((opt->debug>0) && (opt->log!=NULL)) {
  2173.           HTS_LOG(opt,LOG_INFO); fprintf(opt->log,"File successfully written in background: %s"LF,back[i].url_sav); test_flush;
  2174.         }
  2175.         back_maydelete(opt,cache,sback,i);    // May delete backing entry
  2176.       } else {
  2177.         if (!back[i].finalized) {
  2178.           if (1) {
  2179.             /* Ensure deleted or recycled socket */
  2180.             /* BUT DO NOT YET WIPE back[i].r.adr */
  2181.             if ( (opt->debug>1) && (opt->log!=NULL) ) {
  2182.               HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"file %s%s validated (cached, left in memory)"LF,back[i].url_adr,back[i].url_fil); test_flush;
  2183.             }
  2184.             back_maydeletehttp(opt, cache, sback, i);
  2185.           } else {
  2186.             /*
  2187.             NOT YET HANDLED CORRECTLY (READ IN NEW CACHE TO DO)
  2188.             */
  2189.             /* Lock the entry but do not keep the html data in memory (in cache) */
  2190.             if (opt->cache) {
  2191.               htsblk r;
  2192.  
  2193.               /* Ensure deleted or recycled socket */
  2194.               back_maydeletehttp(opt, cache, sback, i);
  2195.               assertf(back[i].r.soc == INVALID_SOCKET);
  2196.  
  2197.               /* Check header */
  2198.               cache_header(opt,cache,back[i].url_adr,back[i].url_fil,&r);
  2199.               if (r.statuscode == HTTP_OK) {
  2200.                 if (back[i].r.soc == INVALID_SOCKET) {
  2201.                   /* Delete buffer and sockets */
  2202.                   deleteaddr(&back[i].r);
  2203.                   deletehttp(&back[i].r);
  2204.                   if ( (opt->debug>1) && (opt->log!=NULL) ) {
  2205.                     HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"file %s%s temporarily left in cache to spare memory"LF,back[i].url_adr,back[i].url_fil); test_flush;
  2206.                   }
  2207.                 }
  2208.               } else {
  2209.                 if ((opt->debug>0) && (opt->log!=NULL)) {
  2210.                   HTS_LOG(opt,LOG_WARNING); fprintf(opt->log,"Unexpected html cache lookup error during back clean"LF); test_flush;
  2211.                 }            
  2212.               }
  2213.               // xxc xxc
  2214.             }
  2215.           }
  2216.         }
  2217.       }
  2218.     } else if (back[i].status == STATUS_ALIVE) {                         // waiting (keep-alive)
  2219.       if (
  2220.         ! back[i].r.keep_alive
  2221.         || back[i].r.soc == INVALID_SOCKET
  2222.         || back[i].r.keep_alive_max < 1
  2223.         || time_local() >= back[i].ka_time_start + back[i].r.keep_alive_t
  2224.         ) {
  2225.         if ((opt->debug>0) && (opt->log!=NULL)) {
  2226.             HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"(Keep-Alive): live socket closed #%d (%s)"LF, 
  2227.             back[i].r.debugid,
  2228.             back[i].url_adr);
  2229.             test_flush;
  2230.         }
  2231.         back_delete(opt,cache,sback, i);    // delete backing entry
  2232.       }
  2233.     }
  2234.   }
  2235.   /* switch connections to live ones */
  2236.   for(i=0;i<back_max;i++) {
  2237.     if (back[i].status == STATUS_READY) {                                   // ready
  2238.       if (back[i].r.soc != INVALID_SOCKET) {
  2239.         back_maydeletehttp(opt,cache,sback, i);
  2240.       }
  2241.     }
  2242.   }
  2243.   /* delete sockets if too many keep-alive'd sockets in background */
  2244.   if (opt->maxsoc > 0) {
  2245.     int max = opt->maxsoc + oneMore;
  2246.     int curr = back_nsoc_overall(sback);
  2247.     if (curr > max) {
  2248.       if ((opt->debug>1) && (opt->log!=NULL)) {
  2249.         HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"(Keep-Alive): deleting #%d sockets"LF, 
  2250.           curr - max); test_flush;
  2251.       }
  2252.     }
  2253.     for(i = 0 ; i < back_max && curr > max ; i++) {
  2254.       if (back[i].status == STATUS_ALIVE) {
  2255.         back_delete(opt,cache,sback, i);    // delete backing entry
  2256.         curr--;
  2257.       }
  2258.     }
  2259.   }
  2260.   /* transfer ready slots to the storage hashtable */
  2261.   {
  2262.     int nxfr = back_cleanup_background(opt,cache,sback);
  2263.     if (nxfr > 0 && (opt->debug>0) && (opt->log!=NULL)) {
  2264.       HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"(htsback): %d slots ready moved to background"LF, nxfr);
  2265.       test_flush;
  2266.     }
  2267.   }
  2268. }
  2269.  
  2270.  
  2271. // attente (gestion des buffers des sockets)
  2272. void back_wait(struct_back* sback,httrackp* opt,cache_back* cache,TStamp stat_timestart) {
  2273.     char catbuff[CATBUFF_SIZE];
  2274.   lien_back* const back = sback->lnk;
  2275.   const int back_max = sback->count;
  2276.   unsigned int i_mod;
  2277.   T_SOC nfds=INVALID_SOCKET;
  2278.   fd_set fds,fds_c,fds_e;     // fds pour lecture, connect (write), et erreur
  2279.   int nsockets;     // nbre sockets
  2280.   LLint max_read_bytes;  // max bytes read per sockets
  2281.   struct timeval tv;
  2282.   int do_wait=0;
  2283.   int gestion_timeout=0;
  2284.   int busy_recv=0;     // pas de donnΘes pour le moment   
  2285.   int busy_state=0;    // pas de connexions
  2286.   int max_loop;  // nombre de boucles max α parcourir..
  2287.   int max_loop_chk=0;
  2288.   unsigned int mod_random = (unsigned int) ( time_local() + HTS_STAT.HTS_TOTAL_RECV );
  2289.  
  2290.   // max. number of loops
  2291.   max_loop=8;
  2292.  
  2293. #if 1
  2294.   // Cleanup the stack to save space!
  2295.   back_clean(opt,cache,sback);
  2296. #endif
  2297.  
  2298.   // recevoir tant qu'il y a des donnΘes (avec un maximum de max_loop boucles)
  2299.   do_wait=0;
  2300.   gestion_timeout=0;
  2301.   do {
  2302.     int max_c;
  2303.     busy_state=busy_recv=0;
  2304.  
  2305. #if 0
  2306.     check_rate(stat_timestart,opt->maxrate);    // vΘrifier taux de transfert
  2307. #endif
  2308.     // inscrire les sockets actuelles, et rechercher l'ID la plus ΘlevΘe
  2309.     FD_ZERO(&fds);
  2310.     FD_ZERO(&fds_c);
  2311.     FD_ZERO(&fds_e);
  2312.     nsockets=0;
  2313.     max_read_bytes=TAILLE_BUFFER;     // maximum bytes that can be read
  2314.     nfds=INVALID_SOCKET;
  2315.  
  2316.     max_c=1;
  2317.     for(i_mod = 0 ; i_mod < (unsigned int) back_max ; i_mod++) {
  2318.     // for(i=0;i<back_max;i++) {
  2319.         unsigned int i = ( i_mod + mod_random ) % ( back_max );
  2320.  
  2321.       // en cas de gestion du connect prΘemptif
  2322. #if HTS_XCONN
  2323.       if (back[i].status==STATUS_CONNECTING) {      // connexion
  2324.         do_wait=1;
  2325.  
  2326.         // noter socket write
  2327.         FD_SET(back[i].r.soc,&fds_c);
  2328.         
  2329.         // noter socket erreur
  2330.         FD_SET(back[i].r.soc,&fds_e);
  2331.  
  2332.         // calculer max
  2333.         if (max_c) {
  2334.           max_c=0;
  2335.           nfds=back[i].r.soc;
  2336.         } else if (back[i].r.soc>nfds) {
  2337.           // ID socket la plus ΘlevΘe
  2338.           nfds=back[i].r.soc;
  2339.         }
  2340.         
  2341.       } else
  2342. #endif
  2343. #if HTS_XGETHOST
  2344.       if (back[i].status==STATUS_WAIT_DNS) {      // attente
  2345.         // rien α faire..
  2346.       } else
  2347. #endif
  2348.       // poll pour la lecture sur les sockets
  2349.       if ((back[i].status>0) && (back[i].status<100)) {  // en rΘception http
  2350.             
  2351. #if BDEBUG==1
  2352.         //printf("....socket in progress: %d\n",back[i].r.soc);
  2353. #endif
  2354.         // non local et non ftp
  2355.         if (!back[i].r.is_file) {
  2356.         //## if (back[i].url_adr[0]!=lOCAL_CHAR) {
  2357.           
  2358.           // vΘrification de sΘcuritΘ
  2359.           if (back[i].r.soc!=INVALID_SOCKET) {  // hey, you never know..
  2360.             do_wait=1;
  2361.             
  2362.             // noter socket read
  2363.             FD_SET(back[i].r.soc,&fds);
  2364.             
  2365.             // noter socket error
  2366.             FD_SET(back[i].r.soc,&fds_e);
  2367.             
  2368.             // incrΘmenter nombre de sockets
  2369.             nsockets++;
  2370.  
  2371.             // calculer max
  2372.             if (max_c) {
  2373.               max_c=0;
  2374.               nfds=back[i].r.soc;
  2375.             } else if (back[i].r.soc>nfds) {
  2376.               // ID socket la plus ΘlevΘe
  2377.               nfds=back[i].r.soc;
  2378.             }
  2379.           } else {
  2380.             back[i].r.statuscode=STATUSCODE_CONNERROR;
  2381.             if (back[i].status==STATUS_CONNECTING)
  2382.               strcpybuff(back[i].r.msg,"Connect Error");
  2383.             else
  2384.               strcpybuff(back[i].r.msg,"Receive Error");
  2385.             back[i].status=STATUS_READY;  // terminΘ
  2386.             back_set_finished(sback, i);
  2387.             if ((opt->debug>0) && (opt->log!=NULL)) {
  2388.               HTS_LOG(opt,LOG_WARNING); fprintf(opt->log,"Unexpected socket error during pre-loop"LF); test_flush;
  2389.             }            
  2390.           }
  2391. #if WIDE_DEBUG
  2392.           else {
  2393.             DEBUG_W("PANIC!!! Socket is invalid in a poll test!\n");
  2394.           }
  2395. #endif
  2396.           
  2397.         }
  2398.         
  2399.       }
  2400.     }    
  2401.     nfds++;
  2402.     
  2403.     if (do_wait) {  // attendre
  2404.       // temps d'attente max: 2.5 seconde
  2405.       tv.tv_sec=HTS_SOCK_SEC;
  2406.       tv.tv_usec=HTS_SOCK_MS;
  2407.       
  2408. #if BDEBUG==1
  2409.       printf("..select\n");
  2410. #endif
  2411.       
  2412.       // poller les sockets-attention au noyau sous Unix..
  2413. #if HTS_WIDE_DEBUG    
  2414.       DEBUG_W("select\n");
  2415. #endif
  2416.       select(nfds,&fds,&fds_c,&fds_e,&tv);
  2417. #if HTS_WIDE_DEBUG    
  2418.       DEBUG_W("select done\n");
  2419. #endif      
  2420.     }
  2421.     
  2422.     // maximum data which can be received for a socket, if limited
  2423.     if (nsockets) {
  2424.       if (opt->maxrate>0) {
  2425.         max_read_bytes = ( check_downloadable_bytes(opt->maxrate) / nsockets );
  2426.         if (max_read_bytes > TAILLE_BUFFER) {
  2427.           /* limit size */
  2428.           max_read_bytes = TAILLE_BUFFER;
  2429.         } else if (max_read_bytes < TAILLE_BUFFER) {
  2430.           /* a small pause */
  2431.           Sleep(10);
  2432.         }
  2433.       }
  2434.     }
  2435.     if (!max_read_bytes)
  2436.       busy_recv=0;
  2437.     
  2438.     // recevoir les donnΘes arrivΘes
  2439.     for(i_mod = 0 ; i_mod < (unsigned int) back_max ; i_mod++) {
  2440.     // for(i=0;i<back_max;i++) {
  2441.         unsigned int i = ( i_mod + mod_random ) % ( back_max );     
  2442.       if (back[i].status>0) {
  2443.         if (!back[i].r.is_file) {  // not file..
  2444.           if (back[i].r.soc!=INVALID_SOCKET) {  // hey, you never know..
  2445.             int err=FD_ISSET(back[i].r.soc,&fds_e);
  2446.             if (err) {
  2447.               if (back[i].r.soc!=INVALID_SOCKET) {
  2448. #if HTS_DEBUG_CLOSESOCK
  2449.                 DEBUG_W("back_wait: deletehttp\n");
  2450. #endif
  2451.                 deletehttp(&back[i].r);
  2452.               }
  2453.               back[i].r.soc=INVALID_SOCKET;
  2454.               back[i].r.statuscode=STATUSCODE_CONNERROR;
  2455.               if (back[i].status==STATUS_CONNECTING)
  2456.                 strcpybuff(back[i].r.msg,"Connect Error");
  2457.               else
  2458.                 strcpybuff(back[i].r.msg,"Receive Error");
  2459.               if (back[i].status == STATUS_ALIVE) {     /* Keep-alive socket */
  2460.                 back_delete(opt,cache,sback, i);
  2461.               } else {
  2462.                 back[i].status=STATUS_READY;  // terminΘ
  2463.                 back_set_finished(sback, i);
  2464.               }
  2465.             }
  2466.           }
  2467.         }
  2468.       }
  2469.       
  2470.       // ---- FLAG WRITE MIS A UN?: POUR LE CONNECT
  2471.       if (back[i].status==STATUS_CONNECTING) {   // attendre connect
  2472.         int dispo=0;
  2473.         // vΘrifier l'existance de timeout-check
  2474.         if (!gestion_timeout)
  2475.           if (back[i].timeout>0)
  2476.             gestion_timeout=1;
  2477.           
  2478.           // connectΘ?
  2479.           dispo=FD_ISSET(back[i].r.soc,&fds_c);
  2480.           if (dispo) {    // ok connected!!
  2481.             busy_state=1;
  2482.             
  2483. #if HTS_USEOPENSSL
  2484.             /* SSL mode */
  2485.             if (SSL_is_available && back[i].r.ssl) {
  2486.               // handshake not yet launched
  2487.               if (!back[i].r.ssl_con) {
  2488.                 SSL_CTX_set_options(openssl_ctx, SSL_OP_ALL);
  2489.                 // new session
  2490.                 back[i].r.ssl_con = SSL_new(openssl_ctx);
  2491.                 if (back[i].r.ssl_con) {
  2492.                   SSL_clear(back[i].r.ssl_con);
  2493.                   if (SSL_set_fd(back[i].r.ssl_con, back[i].r.soc) == 1) {
  2494.                     SSL_set_connect_state(back[i].r.ssl_con);
  2495.                     back[i].status = STATUS_SSL_WAIT_HANDSHAKE;         /* handshake wait */
  2496.                   } else
  2497.                     back[i].r.statuscode=STATUSCODE_SSL_HANDSHAKE;
  2498.                 } else
  2499.                   back[i].r.statuscode=STATUSCODE_SSL_HANDSHAKE;
  2500.               }
  2501.               /* Error */
  2502.               if (back[i].r.statuscode == STATUSCODE_SSL_HANDSHAKE) {
  2503.                 strcpybuff(back[i].r.msg, "bad SSL/TLS handshake");
  2504.                 deletehttp(&back[i].r);
  2505.                 back[i].r.soc=INVALID_SOCKET;
  2506.                 back[i].r.statuscode=STATUSCODE_NON_FATAL;
  2507.                 back[i].status=STATUS_READY;
  2508.                 back_set_finished(sback, i);
  2509.               }
  2510.             }
  2511.             
  2512. #endif
  2513.  
  2514. #if BDEBUG==1
  2515.           printf("..connect ok on socket %d\n",back[i].r.soc);
  2516. #endif
  2517.           
  2518.           if ((back[i].r.soc != INVALID_SOCKET) && (back[i].status==STATUS_CONNECTING)) {
  2519.             /* limit nb. connections/seconds to avoid server overload */
  2520.             /*if (opt->maxconn>0) {
  2521.               Sleep(1000/opt->maxconn);
  2522.             }*/
  2523.             
  2524.             back[i].ka_time_start=time_local();
  2525.             if (back[i].timeout>0) {    // refresh timeout si besoin est
  2526.               back[i].timeout_refresh=back[i].ka_time_start;
  2527.             }
  2528.             if (back[i].rateout>0) {    // le taux de transfert de base sur le dΘbut de la connexion
  2529.               back[i].rateout_time=back[i].ka_time_start;
  2530.             }
  2531.             // envoyer header
  2532.             //if (strcmp(back[i].url_sav,BACK_ADD_TEST)!=0)    // vrai get
  2533.             HTS_STAT.stat_nrequests++;
  2534.             if (!back[i].head_request)
  2535.               http_sendhead(opt, opt->cookie,0,back[i].send_too,back[i].url_adr,back[i].url_fil,back[i].referer_adr,back[i].referer_fil,&back[i].r);         
  2536.             else if (back[i].head_request==2)  // test en GET!
  2537.               http_sendhead(opt, opt->cookie,0,back[i].send_too,back[i].url_adr,back[i].url_fil,back[i].referer_adr,back[i].referer_fil,&back[i].r);         
  2538.             else        // test!
  2539.               http_sendhead(opt, opt->cookie,1,back[i].send_too,back[i].url_adr,back[i].url_fil,back[i].referer_adr,back[i].referer_fil,&back[i].r);         
  2540.             back[i].status=99;  // attendre en tΩte maintenant
  2541.           }
  2542.         }
  2543.         
  2544.         // attente gethostbyname
  2545.       }
  2546. #if HTS_USEOPENSSL
  2547.       else if (SSL_is_available && back[i].status == STATUS_SSL_WAIT_HANDSHAKE) {   // wait for SSL handshake
  2548.         /* SSL mode */
  2549.         if (back[i].r.ssl) {
  2550.           int conn_code;
  2551.           if ((conn_code = SSL_connect(back[i].r.ssl_con)) <= 0) {
  2552.             /* non blocking I/O, will retry */
  2553.             int err_code = SSL_get_error(back[i].r.ssl_con, conn_code);
  2554.             if (
  2555.               (err_code != SSL_ERROR_WANT_READ)
  2556.               &&
  2557.               (err_code != SSL_ERROR_WANT_WRITE)
  2558.               ) {
  2559.               char tmp[256];
  2560.               tmp[0]='\0';
  2561.               ERR_error_string(err_code, tmp);
  2562.               back[i].r.msg[0]='\0';
  2563.               strncatbuff(back[i].r.msg, tmp, sizeof(back[i].r.msg) - 2);
  2564.               if (!strnotempty(back[i].r.msg)) {
  2565.                 sprintf(back[i].r.msg, "SSL/TLS error %d", err_code);
  2566.               }
  2567.               deletehttp(&back[i].r);
  2568.               back[i].r.soc=INVALID_SOCKET;
  2569.               back[i].r.statuscode=STATUSCODE_NON_FATAL;
  2570.               back[i].status=STATUS_READY;
  2571.               back_set_finished(sback, i);
  2572.               }
  2573.           } else {        /* got it! */
  2574.             back[i].status=STATUS_CONNECTING;       // back to waitconnect
  2575.           }
  2576.         } else {
  2577.           strcpybuff(back[i].r.msg, "unexpected SSL/TLS error");
  2578.           deletehttp(&back[i].r);
  2579.           back[i].r.soc=INVALID_SOCKET;
  2580.           back[i].r.statuscode=STATUSCODE_NON_FATAL;
  2581.           back[i].status=STATUS_READY;
  2582.           back_set_finished(sback, i);
  2583.         }
  2584.         
  2585.       }
  2586. #endif
  2587. #if HTS_XGETHOST
  2588.       else if (back[i].status==STATUS_WAIT_DNS) {  // attendre gethostbyname
  2589. #if DEBUGDNS 
  2590.         //printf("status 101 for %s\n",back[i].url_adr);
  2591. #endif
  2592.  
  2593.         if (!gestion_timeout)
  2594.           if (back[i].timeout>0)
  2595.             gestion_timeout=1;
  2596.  
  2597.         if (host_wait(opt, &back[i])) {    // prΩt
  2598.           back[i].status=STATUS_CONNECTING;        // attente connexion
  2599.           if (back[i].timeout>0) {    // refresh timeout si besoin est
  2600.             back[i].timeout_refresh=time_local();
  2601.           }
  2602.           if (back[i].rateout>0) {    // le taux de transfert de base sur le dΘbut de la connexion
  2603.             back[i].rateout_time=time_local();
  2604.           }
  2605.  
  2606.           back[i].r.soc=http_xfopen(opt,0,0,0,back[i].send_too,back[i].url_adr,back[i].url_fil,&(back[i].r));
  2607.           if (back[i].r.soc==INVALID_SOCKET) {
  2608.             back[i].status=STATUS_READY;  // fini, erreur
  2609.             back_set_finished(sback, i);
  2610.             if (back[i].r.soc!=INVALID_SOCKET) {
  2611. #if HTS_DEBUG_CLOSESOCK
  2612.               DEBUG_W("back_wait(2): deletehttp\n");
  2613. #endif
  2614.               deletehttp(&back[i].r);
  2615.             }
  2616.             back[i].r.soc=INVALID_SOCKET;
  2617.             back[i].r.statuscode=STATUSCODE_NON_FATAL;
  2618.             if (strnotempty(back[i].r.msg)==0) 
  2619.               strcpybuff(back[i].r.msg,"Unable to resolve host name");
  2620.           }
  2621.         }
  2622.         
  2623.  
  2624.       // ---- FLAG READ MIS A UN?: POUR LA RECEPTION
  2625.       }
  2626. #endif
  2627. #if USE_BEGINTHREAD
  2628.       // ..rien α faire, c'est magic les threads
  2629. #else
  2630.       else if (back[i].status==STATUS_FTP_TRANSFER) {  // en rΘception ftp
  2631.         if (!fexist(back[i].location_buffer)) {    // terminΘ
  2632.           FILE* fp;
  2633.           fp=fopen(fconcat(OPT_GET_BUFF(opt), back[i].location_buffer,".ok"),"rb");
  2634.           if (fp) {
  2635.             int j=0;
  2636.             fscanf(fp,"%d ",&(back[i].r.statuscode));
  2637.             while(!feof(fp)) {
  2638.               int c = fgetc(fp);
  2639.               if (c!=EOF)
  2640.                 back[i].r.msg[j++]=c;
  2641.             }
  2642.             back[i].r.msg[j++]='\0';
  2643.             fclose(fp);
  2644.             unlink(fconcat(OPT_GET_BUFF(opt), back[i].location_buffer,".ok"));
  2645.             strcpybuff(fconcat(OPT_GET_BUFF(opt), back[i].location_buffer,".ok"),"");
  2646.           } else {
  2647.             strcpybuff(back[i].r.msg,"Unknown ftp result, check if file is ok");
  2648.             back[i].r.statuscode=STATUSCODE_INVALID;
  2649.           }
  2650.           back[i].status=STATUS_READY;
  2651.           back_set_finished(sback, i);
  2652.           // finalize transfer
  2653.           if (back[i].r.statuscode>0) {
  2654.             back_finalize(opt,cache,sback,i);
  2655.           }
  2656.         }
  2657.       }
  2658. #endif
  2659.       else if (back[i].status==STATUS_FTP_READY) {  // ftp ready
  2660.         back[i].status=STATUS_READY;
  2661.         back_set_finished(sback, i);
  2662.         // finalize transfer
  2663.         if (back[i].r.statuscode>0) {
  2664.           back_finalize(opt,cache,sback,i);
  2665.         }
  2666.       }
  2667.       else if ((back[i].status>0) && (back[i].status<1000)) {  // en rΘception http
  2668.         int dispo=0;
  2669.         
  2670.         // vΘrifier l'existance de timeout-check
  2671.         if (!gestion_timeout)
  2672.           if (back[i].timeout>0)
  2673.             gestion_timeout=1;
  2674.           
  2675.           // donnΘes dispo?
  2676.           //## if (back[i].url_adr[0]!=lOCAL_CHAR)
  2677.           if (back[i].r.is_file)
  2678.             dispo=1;
  2679.           else if (back[i].r.ssl)
  2680.             dispo=1;
  2681.           else
  2682.             dispo=FD_ISSET(back[i].r.soc,&fds);
  2683.  
  2684.           // Check transfer rate!
  2685.           if (!max_read_bytes)
  2686.             dispo=0;                // limit transfer rate
  2687.           
  2688.           if (dispo) {    // donnΘes dispo
  2689.             LLint retour_fread;
  2690.             busy_recv=1;    // on rΘcupΦre encore
  2691. #if BDEBUG==1
  2692.             printf("..data available on socket %d\n",back[i].r.soc);
  2693. #endif
  2694.  
  2695.             
  2696.             // range size hack old location
  2697.  
  2698. #if HTS_DIRECTDISK
  2699.             // Court-circuit:
  2700.             // Peut-on stocker le fichier directement sur disque?
  2701.             // Ahh que ca serait vachement mieux et que ahh que la mΘmoire vous dit merci!
  2702.             if (back[i].status) {
  2703.               if (back[i].r.is_write==0) {  // mode mΘmoire
  2704.                 if (back[i].r.adr==NULL) {  // rien n'a ΘtΘ Θcrit
  2705.                   if (!back[i].testmode) {  // pas mode test
  2706.                     if (strnotempty(back[i].url_sav)) {
  2707.                       if (strcmp(back[i].url_fil,"/robots.txt")) {
  2708.                         if (back[i].r.statuscode==HTTP_OK) {  // 'OK'
  2709.                           if (!is_hypertext_mime(opt,back[i].r.contenttype, back[i].url_fil)) {    // pas HTML
  2710.                             if (opt->getmode&2) {    // on peut ecrire des non html
  2711.                               int fcheck=0;
  2712.                               int last_errno = 0;
  2713.                               back[i].r.is_write=1;    // Θcrire
  2714.                               if (back[i].r.compressed
  2715.                                 &&
  2716.                                 /* .gz are *NOT* depacked!! */
  2717.                                 (strfield(get_ext(catbuff,back[i].url_sav),"gz") == 0)
  2718.                                 ) {
  2719.                                 back[i].tmpfile_buffer[0]='\0';
  2720.                                 back[i].tmpfile=tmpnam(back[i].tmpfile_buffer);
  2721.                                 if (back[i].tmpfile != NULL && back[i].tmpfile[0]) {
  2722.                                   if ((back[i].r.out=fopen(back[i].tmpfile,"wb")) == NULL) {
  2723.                                     last_errno = errno;
  2724.                                   }
  2725.                                 }
  2726.                               } else {
  2727.                                 file_notify(opt,back[i].url_adr, back[i].url_fil, back[i].url_sav, 1, 1, back[i].r.notmodified);
  2728.                                 back[i].r.compressed=0;
  2729.                                 if ((back[i].r.out=filecreate(&opt->state.strc, back[i].url_sav)) == NULL) {
  2730.                                   last_errno = errno;
  2731.                                 }
  2732.                               }
  2733.                               if (back[i].r.out==NULL) {
  2734.                                 errno = last_errno;
  2735.                                 if ((fcheck=check_fatal_io_errno())) {
  2736.                                                                     HTS_LOG(opt,LOG_ERROR); fprintf(opt->log,"Mirror aborted: disk full or filesystem problems"LF); test_flush;
  2737.                                   opt->state.exit_xh=-1;   /* fatal error */
  2738.                                 }
  2739.                               }
  2740. #if HDEBUG
  2741.                               printf("direct-disk: %s\n",back[i].url_sav);
  2742. #endif
  2743.                               if ((opt->debug>1) && (opt->log!=NULL)) {
  2744.                                 HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"File received from net to disk: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  2745.                               }
  2746.                               
  2747.                               if (back[i].r.out==NULL) {
  2748.                                 if (opt->log) {
  2749.                                   HTS_LOG(opt,LOG_ERROR);
  2750.                                   fprintf(opt->log,"Unable to save file %s : %s"LF,back[i].url_sav, strerror(last_errno));
  2751.                                   if (fcheck) {
  2752.                                     HTS_LOG(opt,LOG_ERROR);
  2753.                                     fprintf(opt->log,"* * Fatal write error, giving up"LF);
  2754.                                   }
  2755.                                   test_flush;
  2756.                                 }
  2757.                                 back[i].r.is_write=0;    // erreur, abandonner
  2758.                               } else {
  2759. #ifndef _WIN32
  2760.                                 chmod(back[i].url_sav, HTS_ACCESS_FILE);      
  2761. #endif          
  2762.                                 /* create a temporary reference file in case of broken mirror */
  2763.                                 if (back[i].r.out != NULL) {
  2764.                                   if (back_serialize_ref(opt, &back[i]) != 0) {
  2765.                                     if (opt->log != NULL) {
  2766.                                       HTS_LOG(opt,LOG_WARNING); fprintf(opt->log, "Could not create temporary reference file for %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  2767.                                     }
  2768.                                   }
  2769.                                 }
  2770.                               }
  2771.                             } else {  // on coupe tout!
  2772.                               if ((opt->debug>1) && (opt->log!=NULL)) {
  2773.                                 HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"File cancelled (non HTML): %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  2774.                               }
  2775.                               back[i].status=STATUS_READY;  // terminΘ
  2776.                               back_set_finished(sback, i);
  2777.                               if (!back[i].testmode)
  2778.                                 back[i].r.statuscode=STATUSCODE_INVALID;    // EUHH CANCEL
  2779.                               else
  2780.                                 back[i].r.statuscode=STATUSCODE_TEST_OK;    // "TEST OK"
  2781.                               if (back[i].r.soc!=INVALID_SOCKET) {
  2782. #if HTS_DEBUG_CLOSESOCK
  2783.                                 DEBUG_W("back_wait(3): deletehttp\n");
  2784. #endif
  2785.                                 deletehttp(&back[i].r);
  2786.                               }
  2787.                               back[i].r.soc=INVALID_SOCKET;
  2788.                             }
  2789.                           }
  2790.                         }
  2791.                       }
  2792.                     }
  2793.                   }
  2794.                 }
  2795.               }
  2796.             }
  2797. #endif              
  2798.  
  2799.             // rΘception de donnΘes depuis socket ou fichier
  2800.             if (back[i].status) {
  2801.               if (back[i].status==STATUS_WAIT_HEADERS)  // recevoir par bloc de lignes
  2802.                 retour_fread=http_xfread1(&(back[i].r),0);
  2803.               else if (back[i].status==STATUS_CHUNK_WAIT || back[i].status==STATUS_CHUNK_CR) { // recevoir longueur chunk en hexa caractΦre par caractΦre
  2804.                 // backuper pour lire dans le buffer chunk
  2805.                 htsblk r;
  2806.                 memcpy(&r, &(back[i].r), sizeof(htsblk));
  2807.                 back[i].r.is_write=0;                   // mΘmoire
  2808.                 back[i].r.adr=back[i].chunk_adr;        // adresse
  2809.                 back[i].r.size=back[i].chunk_size;      // taille taille chunk
  2810.                 back[i].r.totalsize=-1;                 // total inconnu
  2811.                 back[i].r.out=NULL;
  2812.                 back[i].r.is_file=0;
  2813.                 //
  2814.                 // ligne par ligne
  2815.                 retour_fread=http_xfread1(&(back[i].r),-1);
  2816.                 // modifier et restaurer
  2817.                 back[i].chunk_adr=back[i].r.adr;        // adresse
  2818.                 back[i].chunk_size=back[i].r.size;      // taille taille chunk
  2819.                 memcpy(&(back[i].r), &r, sizeof(htsblk));    // restaurer vΘritable r
  2820.               }
  2821.               else if (back[i].is_chunk) {         // attention chunk, limiter taille α lire
  2822. #if CHUNKDEBUG==1
  2823.                 printf("[%d] read %d bytes\n",(int)back[i].r.soc,(int)min(back[i].r.totalsize-back[i].r.size,max_read_bytes));
  2824. #endif
  2825.                 retour_fread=(int) http_xfread1(&(back[i].r),(int) min(back[i].r.totalsize-back[i].r.size,max_read_bytes));
  2826.               } else              
  2827.                 retour_fread=(int) http_xfread1(&(back[i].r),(int) max_read_bytes);
  2828.                 // retour_fread=http_fread1(&(back[i].r));
  2829.             } else
  2830.               retour_fread=READ_EOF;                    // interruption ou annulation interne (peut ne pas Ωtre une erreur)
  2831.             
  2832.             // Si rΘception chunk, tester si on est pas α la fin!
  2833.             if (back[i].status==1) {
  2834.               if (back[i].is_chunk) {     // attendre prochain chunk
  2835.                 if (back[i].r.size==back[i].r.totalsize) {      // fin chunk!
  2836.                   //printf("chunk end at %d\n",back[i].r.size);
  2837.                   back[i].status=STATUS_CHUNK_CR;  /* fetch ending CRLF */
  2838.                   if (back[i].chunk_adr!=NULL) { 
  2839.                     freet(back[i].chunk_adr); 
  2840.                     back[i].chunk_adr=NULL; 
  2841.                   } 
  2842.                   back[i].chunk_size=0;
  2843.                   retour_fread=0;       // pas d'erreur
  2844. #if CHUNKDEBUG==1
  2845.                   printf("[%d] waiting for current chunk CRLF..\n",(int)back[i].r.soc);
  2846. #endif
  2847.                 }
  2848.               } else if (back[i].r.keep_alive) {
  2849.                 if (back[i].r.size==back[i].r.totalsize) {      // fin!
  2850.                   retour_fread=READ_EOF;       // end
  2851.                 }
  2852.               }
  2853.             }
  2854.             
  2855.             if (retour_fread < 0) {    // fin rΘception
  2856.               back[i].status=STATUS_READY;    // terminΘ
  2857.               back_set_finished(sback, i);
  2858.              /*KA back[i].r.soc=INVALID_SOCKET; */
  2859. #if CHUNKDEBUG==1
  2860.               if (back[i].is_chunk)
  2861.                 printf("[%d] must be the last chunk for %s (connection closed) - %d/%d\n",(int)back[i].r.soc,back[i].url_fil,back[i].r.size,back[i].r.totalsize);
  2862. #endif
  2863.               if (retour_fread < 0 && retour_fread != READ_EOF) {
  2864.                 if (back[i].r.size > 0)
  2865.                   strcpybuff(back[i].r.msg, "Interrupted transfer");
  2866.                 else
  2867.                   strcpybuff(back[i].r.msg, "No data (connection closed)");
  2868.                 back[i].r.statuscode=STATUSCODE_CONNERROR;
  2869.               } else if ((back[i].r.statuscode <= 0) && (strnotempty(back[i].r.msg)==0)) {
  2870. #if HDEBUG
  2871.                 printf("error interruped: %s\n",back[i].r.adr);
  2872. #endif        
  2873.                 if (back[i].r.size>0)
  2874.                   strcpybuff(back[i].r.msg,"Interrupted transfer");
  2875.                 else
  2876.                   strcpybuff(back[i].r.msg,"No data (connection closed)");
  2877.                 back[i].r.statuscode=STATUSCODE_CONNERROR;
  2878.               }
  2879.  
  2880.               // Close socket
  2881.               if (back[i].r.soc!=INVALID_SOCKET) {
  2882. #if HTS_DEBUG_CLOSESOCK
  2883.                 DEBUG_W("back_wait(4): deletehttp\n");
  2884. #endif
  2885.                 /*KA deletehttp(&back[i].r);*/
  2886.                 back_maydeletehttp(opt, cache, sback, i);
  2887.               }
  2888.  
  2889.               // finalize transfer
  2890.               if (back[i].r.statuscode>0
  2891.                 && !IS_DELAYED_EXT(back[i].url_sav)
  2892.                 ) {
  2893.                 back_finalize(opt,cache,sback,i);
  2894.               }
  2895.  
  2896.               if (back[i].r.totalsize>0) {    // tester totalsize
  2897.               //if ((back[i].r.totalsize>0) && (back[i].status==STATUS_WAIT_HEADERS)) {    // tester totalsize
  2898.                 if (back[i].r.totalsize!=back[i].r.size) {  // pas la mΩme!
  2899.                   if (!opt->tolerant) {
  2900.                     //#if HTS_CL_IS_FATAL
  2901.                     deleteaddr(&back[i].r);
  2902.                     if (back[i].r.size<back[i].r.totalsize)
  2903.                       back[i].r.statuscode=STATUSCODE_CONNERROR;        // recatch
  2904.                     sprintf(back[i].r.msg,"Incorrect length ("LLintP" Bytes, "LLintP" expected)",(LLint)back[i].r.size,(LLint)back[i].r.totalsize);
  2905.                   } else {
  2906.                     //#else
  2907.                     // Un warning suffira..
  2908.                     if (cache->log!=NULL) {
  2909.                       fspc(opt,cache->log,"warning"); fprintf(cache->log,"Incorrect length ("LLintP"!="LLintP" expected) for %s%s"LF,(LLint)back[i].r.size,(LLint)back[i].r.totalsize,back[i].url_adr,back[i].url_fil);
  2910.                     }
  2911.                     //#endif
  2912.                   }
  2913.                 }
  2914.               }
  2915. #if BDEBUG==1
  2916.               printf("transfer ok\n");
  2917. #endif
  2918.             } else if (retour_fread > 0) {    // pas d'erreur de rΘception et data
  2919.               if (back[i].timeout>0) {    // refresh timeout si besoin est
  2920.                 back[i].timeout_refresh=time_local();
  2921.               }
  2922.  
  2923.               // Traitement des en tΩtes chunks ou en tΩtes
  2924.               if (back[i].status==STATUS_CHUNK_WAIT || back[i].status==STATUS_CHUNK_CR) {        // rΘception taille chunk en hexa (  aprΦs les en tΩtes, peut ne pas
  2925.                 if (back[i].chunk_size > 0 && back[i].chunk_adr[back[i].chunk_size-1]==10) {
  2926.                   int chunk_size=-1;
  2927.                   char chunk_data[64];
  2928.                   if (back[i].chunk_size<32) {      // pas trop gros
  2929.                     char* chstrip=back[i].chunk_adr;
  2930.                     back[i].chunk_adr[ back[i].chunk_size-1]='\0';    // octet nul 
  2931.                     // skip leading spaces or cr
  2932.                     while(isspace(*chstrip)) chstrip++;
  2933.                     chunk_data[0] = '\0';
  2934.                     strncatbuff(chunk_data, chstrip, sizeof(chunk_data) - 2);
  2935.                     // strip chunk-extension
  2936.                     while( (chstrip = strchr(chunk_data, ';'))) *chstrip='\0';
  2937.                     while( (chstrip = strchr(chunk_data, ' '))) *chstrip='\0';
  2938.                     while( (chstrip = strchr(chunk_data, '\r'))) *chstrip='\0';
  2939. #if CHUNKDEBUG==1
  2940.                     printf("[%d] chunk received and read: %s\n",(int)back[i].r.soc,chunk_data);
  2941. #endif
  2942.                     if (back[i].r.totalsize<0)
  2943.                       back[i].r.totalsize=0;        // initialiser α 0
  2944.                     if (back[i].status==STATUS_CHUNK_WAIT) {   // "real" chunk
  2945.                       if (sscanf(chunk_data,"%x",&chunk_size) == 1) {
  2946.                         if (chunk_size > 0)
  2947.                           back[i].chunk_blocksize = chunk_size;  /* the data block chunk size */
  2948.                                                 else
  2949.                                                     back[i].chunk_blocksize = -1;  /* ending */
  2950.                                                 back[i].r.totalsize+=chunk_size;    // noter taille
  2951.                                                 if (back[i].r.adr != NULL || !back[i].r.is_write) {  // Not to disk
  2952.                                                     back[i].r.adr=(char*) realloct(back[i].r.adr, (size_t)back[i].r.totalsize + 1);
  2953.                                                     if (!back[i].r.adr) {
  2954.                                                         if (cache->log!=NULL) {
  2955.                                                             fprintf(cache->log,"Error: Not enough memory ("LLintP") for %s%s"LF,(LLint)back[i].r.totalsize,back[i].url_adr,back[i].url_fil);
  2956.                                                         }
  2957.                                                     }
  2958.                                                 }
  2959. #if CHUNKDEBUG==1
  2960.                         printf("[%d] chunk length: %d - next total "LLintP":\n",(int)back[i].r.soc,(int)chunk_size,(LLint)back[i].r.totalsize);
  2961. #endif
  2962.                       } else {
  2963.                         if (cache->log!=NULL) {
  2964.                           fprintf(cache->log,"Warning: Illegal chunk (%s) for %s%s"LF,back[i].chunk_adr,back[i].url_adr,back[i].url_fil);
  2965.                         }
  2966.                       }
  2967.                     } else {   /* back[i].status==STATUS_CHUNK_CR : just receiving ending CRLF after data */
  2968.                       if (chunk_data[0] == '\0') {
  2969.                         if (back[i].chunk_blocksize > 0)
  2970.                           chunk_size=(int)back[i].chunk_blocksize;  /* recent data chunk size */
  2971.                         else if (back[i].chunk_blocksize == -1)
  2972.                           chunk_size=0;                        /* ending chunk */
  2973.                         else
  2974.                           chunk_size=1;                        /* fake positive size for 1st chunk history */
  2975. #if CHUNKDEBUG==1
  2976.                         printf("[%d] chunk CRLF seen\n", (int)back[i].r.soc);
  2977. #endif
  2978.                       } else {
  2979.                         if (cache->log!=NULL) {
  2980.                           fprintf(cache->log,"Warning: Illegal chunk CRLF (%s) for %s%s"LF,back[i].chunk_adr,back[i].url_adr,back[i].url_fil);
  2981.                         }
  2982. #if CHUNKDEBUG==1
  2983.                         printf("[%d] chunk CRLF ERROR!! : '%s'\n", (int)back[i].r.soc, chunk_data);
  2984. #endif
  2985.                       }
  2986.                     }
  2987.                   } else {                                  
  2988.                     if (cache->log!=NULL) {
  2989.                       fprintf(cache->log,"Warning: Chunk too big ("LLintP") for %s%s"LF,(LLint)back[i].chunk_size,back[i].url_adr,back[i].url_fil);
  2990.                     }
  2991.                   }
  2992.                     
  2993.                   // ok, continuer sur le body
  2994.                     
  2995.                   // si chunk non nul continuer (ou commencer)
  2996.                   if (back[i].status==STATUS_CHUNK_CR && chunk_size > 0) {
  2997.                     back[i].status = STATUS_CHUNK_WAIT;  /* waiting for next chunk (NN\r\n<data>\r\nNN\r\n<data>..\r\n0\r\n\r\n) */
  2998. #if CHUNKDEBUG==1
  2999.                     printf("[%d] waiting for next chunk\n", (int)back[i].r.soc);
  3000. #endif
  3001.                   } else if (back[i].status==STATUS_CHUNK_WAIT && chunk_size == 0) {  /* final chunk */
  3002.                     back[i].status=STATUS_CHUNK_CR;  /* final CRLF */
  3003. #if CHUNKDEBUG==1
  3004.                     printf("[%d] waiting for final CRLF (chunk)\n", (int)back[i].r.soc);
  3005. #endif
  3006.                   } else if (back[i].status==STATUS_CHUNK_WAIT && chunk_size >= 0) {  /* will fetch data now */
  3007.                     back[i].status=1;     // continuer body    
  3008. #if CHUNKDEBUG==1
  3009.                     printf("[%d] waiting for body (chunk)\n", (int)back[i].r.soc);
  3010. #endif
  3011.                   } else {                /* zero-size-chunk-CRLF (end) or error */
  3012. #if CHUNKDEBUG==1
  3013.                     printf("[%d] chunk end, total: %d\n",(int)back[i].r.soc,back[i].r.size);
  3014. #endif
  3015.                     /* End */
  3016.                     //if (back[i].status==STATUS_CHUNK_CR) {
  3017.                     back[i].status=STATUS_READY;     // fin  
  3018.                     back_set_finished(sback, i);
  3019.                     //}
  3020.  
  3021.                     // finalize transfer if not temporary
  3022.                     if (!IS_DELAYED_EXT(back[i].url_sav)) {
  3023.                       back_finalize(opt,cache,sback,i);
  3024.                     } else {
  3025.                       if (back[i].r.statuscode == HTTP_OK) {
  3026.                         if (cache->log!=NULL) {
  3027.                           fspc(opt,cache->log,"warning"); fprintf(cache->log,"Unexpected incomplete type with 200 code at %s%s"LF, back[i].url_adr, back[i].url_fil);
  3028.                         }
  3029.                       }
  3030.                     }
  3031.                     if (back[i].r.soc!=INVALID_SOCKET) {
  3032. #if HTS_DEBUG_CLOSESOCK
  3033.                       DEBUG_W("back_wait(5): deletehttp\n");
  3034. #endif
  3035.                       /* Error */
  3036.                       if (chunk_size < 0) {
  3037.                         deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  3038.                         deleteaddr(&back[i].r);
  3039.                         back[i].r.statuscode=STATUSCODE_INVALID;
  3040.                         strcpybuff(back[i].r.msg,"Invalid chunk");
  3041. #if CHUNKDEBUG==1
  3042.                         printf("[%d] chunk error\n", (int)back[i].r.soc);
  3043. #endif
  3044.                       } else /* if chunk_size == 0 */ {
  3045. #if CHUNKDEBUG==1
  3046.                         printf("[%d] all chunks now received\n", (int)back[i].r.soc);
  3047. #endif
  3048.                           
  3049.                         /* Tester totalsize en fin de chunk */
  3050.                         if ((back[i].r.totalsize>0)) {    // tester totalsize
  3051.                           if (back[i].r.totalsize!=back[i].r.size) {  // pas la mΩme!
  3052.                             if (!opt->tolerant) {
  3053.                               deleteaddr(&back[i].r);
  3054.                               back[i].r.statuscode=STATUSCODE_INVALID;
  3055.                               strcpybuff(back[i].r.msg,"Incorrect length");
  3056.                             } else {
  3057.                               // Un warning suffira..
  3058.                               if (cache->log!=NULL) {
  3059.                                 fspc(opt,cache->log,"warning"); fprintf(cache->log,"Incorrect length ("LLintP"!="LLintP" expected) for %s%s"LF,(LLint)back[i].r.size,(LLint)back[i].r.totalsize,back[i].url_adr,back[i].url_fil);
  3060.                               }
  3061.                             }
  3062.                           }
  3063.                         }
  3064.                           
  3065.                         /* Oops, trailers! */
  3066.                         if (back[i].r.keep_alive_trailers) {
  3067.                           /* fixme (not yet supported) */
  3068.                         }
  3069.                           
  3070.                       }
  3071.                         
  3072.                         
  3073.                     }
  3074.                   }
  3075.                     
  3076.                   // effacer buffer (chunk en tete)
  3077.                   if (back[i].chunk_adr!=NULL) {
  3078.                     freet(back[i].chunk_adr);
  3079.                     back[i].chunk_adr=NULL;
  3080.                     back[i].chunk_size=0;
  3081.                     // NO! xxback[i].chunk_blocksize = 0;
  3082.                   }
  3083.                   
  3084.                 } // taille buffer chunk > 1 && LF
  3085.                 //
  3086.               } else if (back[i].status==STATUS_WAIT_HEADERS) {        // en tΩtes (avant le chunk si il est prΘsent)
  3087.                 //
  3088.                 if (back[i].r.size>=2) {
  3089.                   // double LF
  3090.                   if (
  3091.                     ((back[i].r.adr[back[i].r.size-1]==10) && (back[i].r.adr[back[i].r.size-2]==10)) 
  3092.                     ||
  3093.                     (back[i].r.adr[0] == '<')    /* bogus server */
  3094.                     ) {
  3095.                     char rcvd[2048];
  3096.                     int ptr=0;
  3097.                     int noFreebuff=0;
  3098.                     
  3099. #if BDEBUG==1
  3100.                     printf("..ok, header received\n");
  3101. #endif
  3102.                     
  3103.                     
  3104.                     /* Hack for zero-length headers */
  3105.                     if (back[i].status != 0 && back[i].r.adr[0] != '<') {
  3106.                       
  3107.                       // ----------------------------------------
  3108.                       // traiter en-tΩte!
  3109.                       // status-line α rΘcupΘrer
  3110.                       ptr+=binput(back[i].r.adr+ptr,rcvd,2000);
  3111.                       if (strnotempty(rcvd)==0) {
  3112.                         /* Bogus CRLF, OR recycled connection and trailing chunk CRLF */
  3113.                         ptr+=binput(back[i].r.adr+ptr,rcvd,2000);
  3114.                       }
  3115.                       
  3116.                       // traiter status-line
  3117.                       treatfirstline(&back[i].r,rcvd);
  3118.                       
  3119. #if HDEBUG
  3120.                       printf("(Buffer) Status-Code=%d\n",back[i].r.statuscode);
  3121. #endif
  3122.                       if (_DEBUG_HEAD) {
  3123.                         if (ioinfo) {
  3124.                           fprintf(ioinfo,"[%d] response for %s%s:\r\ncode=%d\r\n",
  3125.                             back[i].r.debugid, jump_identification(back[i].url_adr),back[i].url_fil,back[i].r.statuscode);
  3126.                           fprintfio(ioinfo,back[i].r.adr,">>> ");
  3127.                           fprintf(ioinfo,"\r\n");
  3128.                           fflush(ioinfo);
  3129.                         }                    // en-tΩte
  3130.                       }
  3131.                       
  3132.                       // header // ** !attention! HTTP/0.9 non supportΘ
  3133.                       do {
  3134.                         ptr+=binput(back[i].r.adr+ptr,rcvd,2000);          
  3135. #if HDEBUG
  3136.                         printf("(buffer)>%s\n",rcvd);      
  3137. #endif
  3138.                         /*
  3139.                         if (_DEBUG_HEAD) {
  3140.                         if (ioinfo) {
  3141.                         fprintf(ioinfo,"(buffer)>%s\r\n",rcvd);      
  3142.                         fflush(ioinfo);
  3143.                         }
  3144.                         }
  3145.                         */
  3146.                         
  3147.                         if (strnotempty(rcvd))
  3148.                           treathead(opt->cookie,back[i].url_adr,back[i].url_fil,&back[i].r,rcvd);  // traiter
  3149.                         
  3150.                         // parfois les serveurs buggΘs renvoient un content-range avec un 200
  3151.                         if (back[i].r.statuscode==HTTP_OK)  // 'OK'
  3152.                           if (strfield(rcvd,"content-range:"))  // Avec un content-range: relisez les RFC..
  3153.                             back[i].r.statuscode=206;    // FORCER A 206 !!!!!
  3154.                           
  3155.                       } while(strnotempty(rcvd));
  3156.                       // ----------------------------------------                    
  3157.  
  3158.                     } else {
  3159.                       // assume text/html, OK
  3160.                       treatfirstline(&back[i].r, back[i].r.adr);
  3161.                       noFreebuff=1;
  3162.                     }
  3163.                       
  3164.                     // Callback
  3165.                     {
  3166.                       int test_head = RUN_CALLBACK6(opt, receivehead, 
  3167.                         back[i].r.adr, back[i].url_adr, back[i].url_fil, back[i].referer_adr, back[i].referer_fil, &back[i].r);
  3168.                       if (test_head!=1) {
  3169.                         if ((opt->debug>0) && (opt->log!=NULL)) {
  3170.                           HTS_LOG(opt,LOG_WARNING); fprintf(opt->log,"External wrapper aborted transfer, breaking connection: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  3171.                         }
  3172.                         back[i].status=STATUS_READY;  // FINI
  3173.                         back_set_finished(sback, i);
  3174.                         deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  3175.                         strcpybuff(back[i].r.msg,"External wrapper aborted transfer");
  3176.                         back[i].r.statuscode = STATUSCODE_INVALID;
  3177.                       }
  3178.                     }
  3179.  
  3180.                     // Free headers memory now
  3181.                     // Actually, save them for informational purpose
  3182.                     if (!noFreebuff) {
  3183.                       char* block = back[i].r.adr;
  3184.                       back[i].r.adr = NULL;
  3185.                       deleteaddr(&back[i].r);
  3186.                       back[i].r.headers = block;
  3187.                     }                  
  3188.                     
  3189.                     /* 
  3190.                     Status code and header-response hacks
  3191.                     */
  3192.  
  3193.                     
  3194.                     // Check response : 203 == 200
  3195.                     if (back[i].r.statuscode==HTTP_NON_AUTHORITATIVE_INFORMATION) {
  3196.                       back[i].r.statuscode=HTTP_OK;       // forcer "OK"
  3197.                     } else if (back[i].r.statuscode == HTTP_CONTINUE) {
  3198.                       back[i].status=STATUS_WAIT_HEADERS;
  3199.                       back[i].r.size=0;
  3200.                       back[i].r.totalsize=0;
  3201.                       back[i].chunk_size=0;
  3202.                       back[i].r.statuscode=STATUSCODE_INVALID;
  3203.                       back[i].r.msg[0]='\0';
  3204.                       if ((opt->debug>1) && (opt->log!=NULL)) {
  3205.                         HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"Status 100 detected for %s%s, continuing headers"LF,back[i].url_adr,back[i].url_fil); test_flush;
  3206.                       }
  3207.                       continue;
  3208.                     }
  3209.                     
  3210.                     /*
  3211.                     Solve "false" 416 problems
  3212.                     */
  3213.                     if (back[i].r.statuscode==416) {  // 'Requested Range Not Satisfiable'
  3214.                       // Example:
  3215.                       // Range: bytes=2830-
  3216.                       // ->
  3217.                       // Content-Range: bytes */2830
  3218.                       if (back[i].range_req_size == back[i].r.crange) {
  3219.                         filenote(&opt->state.strc,back[i].url_sav,NULL);
  3220.                         file_notify(opt,back[i].url_adr, back[i].url_fil, back[i].url_sav, 0, 0, back[i].r.notmodified);
  3221.                         deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  3222.                         back[i].status=STATUS_READY;    // READY
  3223.                         back_set_finished(sback, i);
  3224.                         back[i].r.size=back[i].r.totalsize=back[i].range_req_size;
  3225.                         back[i].r.statuscode=HTTP_NOT_MODIFIED;     // NOT MODIFIED
  3226.                         if ((opt->debug>1) && (opt->log!=NULL)) {
  3227.                           HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"File seems complete (good 416 message), breaking connection: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  3228.                         }
  3229.                       }
  3230.                     }
  3231.                     
  3232.                     // transform 406 into 200 ; we'll catch embedded links inside the choice page
  3233.                     if (back[i].r.statuscode==406) {  // 'Not Acceptable'
  3234.                       back[i].r.statuscode=HTTP_OK;
  3235.                     }
  3236.  
  3237.                                         // 'do not erase already downloaded file'
  3238.                                         // on an updated file
  3239.                                         // with an error : consider a 304 error
  3240.                                         if (!opt->delete_old) {
  3241.                                             if (HTTP_IS_ERROR(back[i].r.statuscode) && back[i].is_update && !back[i].testmode) {
  3242.                                                 if (back[i].url_sav[0] && fexist(back[i].url_sav)) {
  3243.                                                     if ((opt->debug>1) && (opt->log!=NULL)) {
  3244.                                                         HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"Error ignored %d (%s) because of 'no purge' option for %s%s"LF,back[i].r.statuscode,back[i].r.msg,back[i].url_adr,back[i].url_fil); test_flush;
  3245.                                                     }
  3246.                                                     back[i].r.statuscode = HTTP_NOT_MODIFIED;
  3247.                                                     deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  3248.                                                 }
  3249.                                             }
  3250.                                         }
  3251.  
  3252.                                         // Various hacks to limit re-transfers when updating a mirror
  3253.                     // Force update if same size detected
  3254.                     if (opt->sizehack) {
  3255.                       // We already have the file
  3256.                       // and ask the remote server for an update
  3257.                       // Some servers, especially dynamic pages severs, always
  3258.                       // answer that the page has been modified since last visit
  3259.                       // And answer with a 200 (OK) response, and the same page
  3260.                       // If the size is the same, and the option has been set, we assume
  3261.                       // that the file is identical - and therefore let's break the connection
  3262.                       if (back[i].is_update) {          // mise α jour
  3263.                         if (back[i].r.statuscode==HTTP_OK && !back[i].testmode) {  // 'OK'
  3264.                           htsblk r = cache_read(opt,cache,back[i].url_adr,back[i].url_fil,NULL,NULL);    // lire entrΘe cache
  3265.                           if (r.statuscode == HTTP_OK) {  // OK pas d'erreur cache
  3266.                             LLint len1,len2;
  3267.                             len1=r.totalsize;
  3268.                             len2=back[i].r.totalsize;
  3269.                             if (r.size>0)
  3270.                               len1=r.size;
  3271.                             if (len1>0) {
  3272.                               if (len1 == len2) {             // tailles identiques
  3273.                                 back[i].r.statuscode=HTTP_NOT_MODIFIED;     // forcer NOT MODIFIED
  3274.                                 deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  3275.                                 if ((opt->debug>1) && (opt->log!=NULL)) {
  3276.                                   HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"File seems complete (same size), breaking connection: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  3277.                                 }
  3278.                               }
  3279.                             }
  3280.                           } else {
  3281.                             if (opt->log!=NULL) {
  3282.                               HTS_LOG(opt,LOG_WARNING); fprintf(opt->log,"File seems complete (same size), but there was a cache read error: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  3283.                             }
  3284.                           }
  3285.                           if (r.adr) {
  3286.                             freet(r.adr);
  3287.                                                         r.adr = NULL;
  3288.                           }
  3289.                         }
  3290.                       }
  3291.                     }
  3292.                     
  3293.                     // Various hacks to limit re-transfers when updating a mirror
  3294.                     // Detect already downloaded file (with another browser, for example)
  3295.                     if (opt->sizehack) {
  3296.                       if (!back[i].is_update) {          // mise α jour
  3297.                         if (back[i].r.statuscode==HTTP_OK && !back[i].testmode) {  // 'OK'
  3298.                           if (!is_hypertext_mime(opt,back[i].r.contenttype, back[i].url_fil)) {    // not HTML
  3299.                             if (strnotempty(back[i].url_sav)) {  // target found
  3300.                               int size = fsize(back[i].url_sav);  // target size
  3301.                               if (size >= 0) {
  3302.                                 if (back[i].r.totalsize == size) {  // same size!
  3303.                                   deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  3304.                                   back[i].status=STATUS_READY;    // READY
  3305.                                   back_set_finished(sback, i);
  3306.                                   back[i].r.size=back[i].r.totalsize;
  3307.                                   filenote(&opt->state.strc,back[i].url_sav,NULL);
  3308.                                   file_notify(opt,back[i].url_adr, back[i].url_fil, back[i].url_sav, 0, 0, back[i].r.notmodified);
  3309.                                   back[i].r.statuscode=HTTP_NOT_MODIFIED;     // NOT MODIFIED
  3310.                                   if ((opt->debug>1) && (opt->log!=NULL)) {
  3311.                                     HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"File seems complete (same size file discovered), breaking connection: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  3312.                                   }
  3313.                                 }
  3314.                               }
  3315.                             }
  3316.                           }
  3317.                         }
  3318.                       }
  3319.                     }
  3320.                     
  3321.                     // Various hacks to limit re-transfers when updating a mirror
  3322.                     // Detect bad range: header
  3323.                     if (opt->sizehack) {
  3324.                       // We have request for a partial file (with a 'Range: NNN-' header)
  3325.                       // and received a complete file notification (200), with 'Content-length: NNN'
  3326.                       // it might be possible that we had the complete file
  3327.                       // this is the case in *most* cases, so break the connection
  3328.                       if (back[i].r.is_write==0) {  // mode mΘmoire
  3329.                         if (back[i].r.adr==NULL) {  // rien n'a ΘtΘ Θcrit
  3330.                           if (!back[i].testmode) {  // pas mode test
  3331.                             if (strnotempty(back[i].url_sav)) {
  3332.                               if (strcmp(back[i].url_fil,"/robots.txt")) {
  3333.                                 if (back[i].r.statuscode==HTTP_OK) {  // 'OK'
  3334.                                   if (!is_hypertext_mime(opt,back[i].r.contenttype, back[i].url_fil)) {    // pas HTML
  3335.                                     if (back[i].r.statuscode==HTTP_OK) {      // "OK"
  3336.                                       if (back[i].range_req_size>0) {     // but Range: requested
  3337.                                         if (back[i].range_req_size == back[i].r.totalsize) {    // And same size
  3338. #if HTS_DEBUG_CLOSESOCK
  3339.                                           DEBUG_W("back_wait(skip_range): deletehttp\n");
  3340. #endif
  3341.                                           deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  3342.                                           back[i].status=STATUS_READY;    // READY
  3343.                                           back_set_finished(sback, i);
  3344.                                           back[i].r.size=back[i].r.totalsize;
  3345.                                           filenote(&opt->state.strc,back[i].url_sav,NULL);
  3346.                                           file_notify(opt,back[i].url_adr, back[i].url_fil, back[i].url_sav, 0, 0, back[i].r.notmodified);
  3347.                                           back[i].r.statuscode=HTTP_NOT_MODIFIED;     // NOT MODIFIED
  3348.                                           if ((opt->debug>1) && (opt->log!=NULL)) {
  3349.                                             HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"File seems complete (reget failed), breaking connection: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  3350.                                           }
  3351.                                         }
  3352.                                       }
  3353.                                     }
  3354.                                     
  3355.                                   }
  3356.                                 }
  3357.                               }
  3358.                             }
  3359.                           }
  3360.                         }
  3361.                       }
  3362.                     }
  3363.                     // END - Various hacks to limit re-transfers when updating a mirror
  3364.  
  3365.                     /* 
  3366.                     End of status code and header-response hacks
  3367.                     */
  3368.  
  3369.                     
  3370.                     
  3371.                     /* Interdiction taille par le wizard? */
  3372.                     if (back[i].r.soc!=INVALID_SOCKET) {
  3373.                       if (!back_checksize(opt,&back[i],1)) {
  3374.                         back[i].status=STATUS_READY;  // FINI
  3375.                         back_set_finished(sback, i);
  3376.                         back[i].r.statuscode=STATUSCODE_TOO_BIG;
  3377.                         deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  3378.                         if (!back[i].testmode)
  3379.                           strcpybuff(back[i].r.msg,"File too big");
  3380.                         else
  3381.                           strcpybuff(back[i].r.msg,"Test: File too big");
  3382.                       }
  3383.                     }
  3384.                     
  3385.                     /* sinon, continuer */
  3386.                     /* if (back[i].r.soc!=INVALID_SOCKET) {   // ok rΘcupΘrer body? */
  3387.                     // head: terminΘ
  3388.                     if (back[i].head_request) {
  3389.                       if ((opt->debug>1) && (opt->log!=NULL)) {
  3390.                         HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"Tested file: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  3391.                       }
  3392. #if HTS_DEBUG_CLOSESOCK
  3393.                       DEBUG_W("back_wait(head request): deletehttp\n");
  3394. #endif
  3395.                       // Couper connexion
  3396.                       if (!back[i].http11) {    /* NO KA */
  3397.                         deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  3398.                       }
  3399.                       back[i].status=STATUS_READY;  // terminΘ
  3400.                       back_set_finished(sback, i);
  3401.                     }
  3402.                     // traiter une Θventuelle erreur 304 (cache α jour utilisable)
  3403.                     else if (back[i].r.statuscode==HTTP_NOT_MODIFIED) {  // document α jour dans le cache
  3404.                       // lire dans le cache
  3405.                       // ** NOTE: pas de vΘrif de la taille ici!!
  3406. #if HTS_DEBUG_CLOSESOCK
  3407.                       DEBUG_W("back_wait(file is not modified): deletehttp\n");
  3408. #endif
  3409.                       /* clear everything but connection: switch, close, and reswitch */
  3410.                       {
  3411.                         htsblk tmp;
  3412.                         memset(&tmp, 0, sizeof(tmp));
  3413.                         back_connxfr(&back[i].r, &tmp);
  3414.                         back[i].r=cache_read(opt,cache,back[i].url_adr,back[i].url_fil,back[i].url_sav,back[i].location_buffer);
  3415.                         back[i].r.location=back[i].location_buffer;
  3416.                         back_connxfr(&tmp,&back[i].r);
  3417.                       }
  3418.  
  3419.                       // hack:
  3420.                       // In case of 'if-unmodified-since' hack, a 304 status can be sent
  3421.                       // then, force 'ok' status
  3422.                       if (back[i].r.statuscode == STATUSCODE_INVALID) {
  3423.                         if (fexist(back[i].url_sav)) {
  3424.                           back[i].r.statuscode=HTTP_OK;     // OK
  3425.                           strcpybuff(back[i].r.msg, "OK (cached)");
  3426.                           back[i].r.is_file=1;
  3427.                           back[i].r.totalsize = back[i].r.size = fsize(back[i].url_sav);
  3428.                           get_httptype(opt,back[i].r.contenttype, back[i].url_sav, 1);
  3429.                           if ((opt->debug>0) && (opt->log!=NULL)) {
  3430.                             HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"Not-modified status without cache guessed: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  3431.                           }
  3432.                         }
  3433.                       }
  3434.  
  3435.                       // Status is okay?
  3436.                       if (back[i].r.statuscode!=-1) { // pas d'erreur de lecture
  3437.                         back[i].status=STATUS_READY;         // OK prΩt
  3438.                         back_set_finished(sback, i);
  3439.                         back[i].r.notmodified=1;  // NON modifiΘ!
  3440.                         if ((opt->debug>0) && (opt->log!=NULL)) {
  3441.                           HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"File loaded after test from cache: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  3442.                         }
  3443.  
  3444.                         // finalize
  3445.                         //file_notify(back[i].url_adr, back[i].url_fil, back[i].url_sav, 0, 0, back[i].r.notmodified);        // not modified
  3446.                         if (back[i].r.statuscode>0) {
  3447.                           back_finalize(opt,cache,sback,i);
  3448.                         }
  3449.                         
  3450. #if DEBUGCA
  3451.                         printf("..document α jour aprΦs requΦte: %s%s\n",back[i].url_adr,back[i].url_fil);
  3452. #endif
  3453.                         
  3454.                         //printf(">%s status %d\n",back[p].r.contenttype,back[p].r.statuscode);
  3455.                       } else {  // erreur
  3456.                         back[i].status=STATUS_READY;  // terminΘ
  3457.                         back_set_finished(sback, i);
  3458.                         //printf("erreur cache\n");
  3459.                         
  3460.                       } 
  3461.                       
  3462. /********** NO - must complete the body! ********** */
  3463. #if 0
  3464.                     } else if (HTTP_IS_REDIRECT(back[i].r.statuscode)
  3465.                       || (back[i].r.statuscode==412)
  3466.                       || (back[i].r.statuscode==416)
  3467.                       ) {   // Ne pas prendre le html, erreurs connues et gΘrΘes
  3468. #if HTS_DEBUG_CLOSESOCK
  3469.                       DEBUG_W("back_wait(301,302,303,307,412,416..): deletehttp\n");
  3470. #endif
  3471.                       // Couper connexion
  3472.                       /*KA deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;*/
  3473.                       back_maydeletehttp(opt, cache, sback, i);
  3474.  
  3475.                       back[i].status=STATUS_READY;  // terminΘ
  3476.                       back_set_finished(sback, i);
  3477.                       // finalize
  3478.                       if (back[i].r.statuscode>0) {
  3479.                         back_finalize(opt,cache,sback,i);
  3480.                       }
  3481. #endif
  3482. /********** **************************** ********** */
  3483.                     } else {    // il faut aller le chercher
  3484.                       
  3485.                       // effacer buffer (requΦte)
  3486.                       if (!noFreebuff) {
  3487.                         deleteaddr(&back[i].r);
  3488.                         back[i].r.size=0;
  3489.                       }
  3490.                       
  3491.                       // traiter 206 (partial content)
  3492.                       // xxc SI CHUNK VERIFIER QUE CA MARCHE??
  3493.                       if (back[i].r.statuscode==206) {  // on nous envoie un morceau (la fin) coz une partie sur disque!
  3494.                         off_t sz=fsize(back[i].url_sav);
  3495. #if HDEBUG
  3496.                         printf("partial content: "LLintP" on disk..\n",(LLint)sz);
  3497. #endif
  3498.                         if (sz>=0) {
  3499.                           if (!is_hypertext_mime(opt,back[i].r.contenttype, back[i].url_sav)) {    // pas HTML
  3500.                             if (opt->getmode&2) {    // on peut ecrire des non html  **sinon ben euhh sera interceptΘ plus loin, donc rap sur ce qui va sortir**
  3501.                               filenote(&opt->state.strc,back[i].url_sav,NULL);    // noter fichier comme connu
  3502.                               file_notify(opt,back[i].url_adr, back[i].url_fil, back[i].url_sav, 0, 1, back[i].r.notmodified);
  3503.                               back[i].r.out=fopen(fconv(catbuff,back[i].url_sav),"ab");  // append
  3504.                               if (back[i].r.out) {
  3505.                                 back[i].r.is_write=1;    // Θcrire
  3506.                                 back[i].r.size=sz;    // dΘja Θcrit
  3507.                                 back[i].r.statuscode=HTTP_OK;  // Forcer 'OK'
  3508.                                 if (back[i].r.totalsize>0)
  3509.                                   back[i].r.totalsize+=sz;    // plus en fait
  3510.                                 fseek(back[i].r.out,0,SEEK_END);  // α la fin
  3511.                                 /* create a temporary reference file in case of broken mirror */
  3512.                                 if (back_serialize_ref(opt, &back[i]) != 0) {
  3513.                                   if (opt->log != NULL) {
  3514.                                     HTS_LOG(opt,LOG_WARNING); fprintf(opt->log, "Could not create temporary reference file for %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  3515.                                   }
  3516.                                 }
  3517. #if HDEBUG
  3518.                                 printf("continue interrupted file\n");
  3519. #endif
  3520.                               } else {    // On est dans la m**
  3521.                                 back[i].status=STATUS_READY;  // terminΘ (voir plus loin)
  3522.                                 back_set_finished(sback, i);
  3523.                                 strcpybuff(back[i].r.msg,"Can not open partial file");
  3524.                               }
  3525.                             }
  3526.                           } else {    // mΘmoire
  3527.                             FILE* fp=fopen(fconv(catbuff,back[i].url_sav),"rb");
  3528.                             if (fp) {
  3529.                               LLint alloc_mem=sz + 1;
  3530.                               if (back[i].r.totalsize>0)
  3531.                                 alloc_mem+=back[i].r.totalsize;            // AJOUTER RESTANT!
  3532.                               if ( deleteaddr(&back[i].r) && (back[i].r.adr=(char*) malloct((size_t)alloc_mem)) ) {
  3533.                                 back[i].r.size=sz;
  3534.                                 if (back[i].r.totalsize>0)
  3535.                                   back[i].r.totalsize+=sz;    // plus en fait
  3536.                                 if (( fread(back[i].r.adr,1,sz,fp)) != sz) {
  3537.                                   back[i].status=STATUS_READY;  // terminΘ (voir plus loin)
  3538.                                   back_set_finished(sback, i);
  3539.                                   strcpybuff(back[i].r.msg,"Can not read partial file");
  3540.                                 } else {
  3541.                                   back[i].r.statuscode=HTTP_OK;  // Forcer 'OK'
  3542. #if HDEBUG
  3543.                                   printf("continue in mem interrupted file\n");
  3544. #endif
  3545.                                 }
  3546.                               } else {
  3547.                                 back[i].status=STATUS_READY;  // terminΘ (voir plus loin)
  3548.                                 back_set_finished(sback, i);
  3549.                                 strcpybuff(back[i].r.msg,"No memory for partial file");
  3550.                               }
  3551.                               fclose(fp);
  3552.                             } else {  // Argh.. 
  3553.                               back[i].status=STATUS_READY;  // terminΘ (voir plus loin)
  3554.                               back_set_finished(sback, i);
  3555.                               strcpybuff(back[i].r.msg,"Can not open partial file");
  3556.                             }
  3557.                           }
  3558.                         } else {    // Non trouvΘ??
  3559.                           back[i].status=STATUS_READY;  // terminΘ (voir plus loin)
  3560.                           back_set_finished(sback, i);
  3561.                           strcpybuff(back[i].r.msg,"Can not find partial file");
  3562.                         }
  3563.                         // Erreur?
  3564.                         if (back[i].status==STATUS_READY) {
  3565.                           if (back[i].r.soc!=INVALID_SOCKET) {
  3566. #if HTS_DEBUG_CLOSESOCK
  3567.                             DEBUG_W("back_wait(206 solve problems): deletehttp\n");
  3568. #endif
  3569.                             deletehttp(&back[i].r);
  3570.                           }
  3571.                           back[i].r.soc=INVALID_SOCKET;
  3572.                           //back[i].r.statuscode=206;  ????????
  3573.                           back[i].r.statuscode=STATUSCODE_NON_FATAL;
  3574.                           if (strnotempty(back[i].r.msg))
  3575.                             strcpybuff(back[i].r.msg,"Error attempting to solve status 206 (partial file)");
  3576.                         }
  3577.                       }
  3578.                       
  3579.                       if (back[i].status!=0) {  // non terminΘ (erreur)
  3580.                         if (!back[i].testmode) {    // fichier normal
  3581.                           
  3582.                           if (back[i].r.empty /* ?? && back[i].r.statuscode==HTTP_OK */) {  // empty response
  3583.                             // Couper connexion
  3584.                             back_maydeletehttp(opt, cache, sback, i);
  3585.                             /* KA deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET; */
  3586.                             back[i].status=STATUS_READY;  // terminΘ
  3587.                             back_set_finished(sback, i);
  3588.                             if ( deleteaddr(&back[i].r) && (back[i].r.adr=(char*) malloct( 2)) ) {
  3589.                               back[i].r.adr[0] = 0;
  3590.                             }
  3591.                             back_finalize(opt,cache,sback,i);
  3592.                           }
  3593.                           else if (!back[i].r.is_chunk) {    // pas de chunk
  3594.                             //if (back[i].r.http11!=2) {    // pas de chunk
  3595.                             back[i].is_chunk=0;
  3596.                             back[i].status=1;     // start body
  3597.                           } else {
  3598. #if CHUNKDEBUG==1
  3599.                             printf("[%d] chunk encoding detected %s..\n",(int)back[i].r.soc, back[i].url_fil);
  3600. #endif
  3601.                             back[i].is_chunk=1;
  3602.                             back[i].chunk_adr=NULL;
  3603.                             back[i].chunk_size=0;
  3604.                             back[i].chunk_blocksize=0;
  3605.                             back[i].status=STATUS_CHUNK_WAIT;    // start body wait chunk
  3606.                             back[i].r.totalsize=0;   /* devalidate size! (rfc) */
  3607.                           }
  3608.                           if (back[i].rateout>0) {
  3609.                             back[i].rateout_time=time_local();  // refresh pour transfer rate
  3610.                           }
  3611. #if HDEBUG
  3612.                           printf("(buffer) start body!\n");
  3613. #endif
  3614.                         } else {     // mode test, ne pas passer en 1!!
  3615.                           back[i].status=STATUS_READY;    // READY
  3616.                           back_set_finished(sback, i);
  3617. #if HTS_DEBUG_CLOSESOCK
  3618.                           DEBUG_W("back_wait(test ok): deletehttp\n");
  3619. #endif
  3620.                           deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  3621.                           if (back[i].r.statuscode==HTTP_OK) {
  3622.                             strcpybuff(back[i].r.msg,"Test: OK");
  3623.                             back[i].r.statuscode=STATUSCODE_TEST_OK;    // test rΘussi
  3624.                           }
  3625.                           else {    // test a ΘchouΘ, on ne change rien sauf que l'erreur est α titre indicatif
  3626.                             char tempo[1000];
  3627.                             strcpybuff(tempo,back[i].r.msg);
  3628.                             strcpybuff(back[i].r.msg,"Test: ");
  3629.                             strcatbuff(back[i].r.msg,tempo);
  3630.                           }
  3631.                           
  3632.                         }
  3633.                       }
  3634.                       
  3635.                       } 
  3636.                       
  3637.                       /*}*/
  3638.                       
  3639.                   }  // si LF
  3640.                 }  // r.size>2
  3641.               }  // si == 99
  3642.               
  3643.             } // si pas d'erreurs
  3644. #if BDEBUG==1
  3645.             printf("bytes overall: %d\n",back[i].r.size);
  3646. #endif
  3647.           }  // donnΘes dispo
  3648.           
  3649.           // en cas d'erreur cl, supprimer Θventuel fichier sur disque
  3650. #if HTS_REMOVE_BAD_FILES
  3651.           if (back[i].status<0) {
  3652.             if (!back[i].testmode) {    // pas en test
  3653.               unlink(back[i].url_sav);    // Θliminer fichier (endommagΘ)
  3654.               //printf("&& %s\n",back[i].url_sav);
  3655.             }
  3656.           }
  3657. #endif
  3658.  
  3659.           /* funny log for commandline users */
  3660.           //if (!opt->quiet) {  
  3661.           // petite animation
  3662.           if (opt->verbosedisplay==1) {
  3663.             if (back[i].status==STATUS_READY) {
  3664.               if (back[i].r.statuscode==HTTP_OK)
  3665.                 printf("* %s%s ("LLintP" bytes) - OK"VT_CLREOL"\r",back[i].url_adr,back[i].url_fil,(LLint)back[i].r.size);
  3666.               else
  3667.                 printf("* %s%s ("LLintP" bytes) - %d"VT_CLREOL"\r",back[i].url_adr,back[i].url_fil,(LLint)back[i].r.size,back[i].r.statuscode);
  3668.               fflush(stdout);
  3669.             }
  3670.           }
  3671.           //}
  3672.           
  3673.  
  3674.       } // status>0
  3675.     }  // for
  3676.     
  3677.     // vΘrifier timeouts
  3678.     if (gestion_timeout) {
  3679.       TStamp act;
  3680.       act=time_local();    // temps en secondes
  3681.       for(i_mod = 0 ; i_mod < (unsigned int) back_max ; i_mod++) {
  3682.       // for(i=0;i<back_max;i++) {
  3683.         unsigned int i = ( i_mod + mod_random ) % ( back_max );     
  3684.         if (back[i].status>0) {  // rΘception/connexion/..
  3685.           if (back[i].timeout>0) {
  3686.             //printf("time check %d\n",((int) (act-back[i].timeout_refresh))-back[i].timeout);
  3687.             if (((int) (act-back[i].timeout_refresh))>=back[i].timeout) {
  3688.               if (back[i].r.soc!=INVALID_SOCKET) {
  3689. #if HTS_DEBUG_CLOSESOCK
  3690.                 DEBUG_W("back_wait(timeout): deletehttp\n");
  3691. #endif
  3692.                 deletehttp(&back[i].r);
  3693.               }
  3694.               back[i].r.soc=INVALID_SOCKET;
  3695.               back[i].r.statuscode=STATUSCODE_TIMEOUT;
  3696.               if (back[i].status==STATUS_CONNECTING)
  3697.                 strcpybuff(back[i].r.msg,"Connect Time Out");
  3698.               else if (back[i].status==STATUS_WAIT_DNS)
  3699.                 strcpybuff(back[i].r.msg,"DNS Time Out");
  3700.               else
  3701.                 strcpybuff(back[i].r.msg,"Receive Time Out");
  3702.               back[i].status=STATUS_READY;  // terminΘ
  3703.               back_set_finished(sback, i);
  3704.             } else if ((back[i].rateout>0) && (back[i].status<99)) {
  3705.               if (((int) (act-back[i].rateout_time))>=HTS_WATCHRATE) {   // checker au bout de 15s
  3706.                 if ( (int) ((back[i].r.size)/(act-back[i].rateout_time)) < back[i].rateout ) {  // trop lent
  3707.                   back[i].status=STATUS_READY;  // terminΘ
  3708.                   back_set_finished(sback, i);
  3709.                   if (back[i].r.soc!=INVALID_SOCKET) {
  3710. #if HTS_DEBUG_CLOSESOCK
  3711.                     DEBUG_W("back_wait(rateout): deletehttp\n");
  3712. #endif
  3713.                     deletehttp(&back[i].r);
  3714.                   }
  3715.                   back[i].r.soc=INVALID_SOCKET;
  3716.                   back[i].r.statuscode=STATUSCODE_SLOW;
  3717.                   strcpybuff(back[i].r.msg,"Transfer Rate Too Low");
  3718.                 }
  3719.               }
  3720.             }
  3721.           }
  3722.         }
  3723.       }
  3724.     }
  3725.     max_loop--;
  3726.     max_loop_chk++;
  3727.   } while((busy_state) && (busy_recv) && (max_loop>0));
  3728.   if ((!busy_recv) && (!busy_state)) {
  3729.     if (max_loop_chk>=1) {
  3730.       Sleep(10);    // un tite pause pour Θviter les lag..
  3731.     }
  3732.   }
  3733. }
  3734.  
  3735. int back_checksize(httrackp* opt,lien_back* eback,int check_only_totalsize) {
  3736.   LLint size_to_test;
  3737.   if (check_only_totalsize)
  3738.     size_to_test=eback->r.totalsize;
  3739.   else
  3740.     size_to_test=max(eback->r.totalsize,eback->r.size);
  3741.   if (size_to_test>=0) {
  3742.     
  3743.     /* Interdiction taille par le wizard? */
  3744.     if (hts_testlinksize(opt,eback->url_adr,eback->url_fil,eback->r.totalsize/1024)==-1) {
  3745.       return 0;     /* interdit */
  3746.     }                     
  3747.     
  3748.     /* vΘrifier taille classique (heml et non html) */
  3749.     if ((istoobig(opt,size_to_test,eback->maxfile_html,eback->maxfile_nonhtml,eback->r.contenttype))) {
  3750.       return 0;     /* interdit */
  3751.     }
  3752.   }
  3753.   return 1;
  3754. }
  3755.  
  3756. int back_checkmirror(httrackp* opt) {
  3757.   // Check max size
  3758.   if ((opt->maxsite>0) && (HTS_STAT.stat_bytes >= opt->maxsite)) {
  3759.     if (!opt->state.stop) {  /* not yet stopped */
  3760.       if (opt->log) {
  3761.         fprintf(opt->log,"More than "LLintP" bytes have been transfered.. giving up"LF,(LLint)opt->maxsite);
  3762.         test_flush;
  3763.       }
  3764.       /* cancel mirror smoothly */
  3765.       hts_request_stop(opt, 0);
  3766.     }
  3767.     return 1;  /* don'k break mirror too sharply for size limits, but stop requested */
  3768.     /*return 0;
  3769.     */
  3770.   }
  3771.   // Check max time
  3772.   if ((opt->maxtime>0) && ((time_local()-HTS_STAT.stat_timestart)>opt->maxtime)) {            
  3773.     if (opt->log) {
  3774.       fprintf(opt->log,"More than %d seconds passed.. giving up"LF,opt->maxtime);
  3775.       test_flush;
  3776.     }
  3777.     return 0;  /* stop now */
  3778.   }
  3779.   return 1;   /* Ok, go on */
  3780. }
  3781.  
  3782.  
  3783. // octets transfΘrΘs + add
  3784. LLint back_transfered(LLint nb,struct_back* sback) {
  3785.   lien_back* const back = sback->lnk;
  3786.   const int back_max = sback->count;
  3787.   int i;
  3788.   // ajouter octets en instance
  3789.   for(i=0;i<back_max;i++)
  3790.     if ((back[i].status>0) && (back[i].status<99 || back[i].status>=1000))
  3791.       nb += back[i].r.size;
  3792.   // stored (ready) slots
  3793.   if (sback->ready != NULL) {
  3794. #ifndef HTS_NO_BACK_ON_DISK
  3795.         nb += sback->ready_size_bytes;
  3796. #else
  3797.     struct_inthash_enum e = inthash_enum_new(sback->ready);
  3798.     inthash_chain* item;
  3799.     while((item = inthash_enum_next(&e))) {
  3800.       lien_back* ritem = (lien_back*) item->value.ptr;
  3801.       if ((ritem->status>0) && (ritem->status<99 || ritem->status>=1000))
  3802.         nb += ritem->r.size;
  3803.     }
  3804. #endif
  3805.   }
  3806.   return nb;      
  3807. }
  3808.  
  3809. // infos backing
  3810. // j: 1 afficher sockets 2 afficher autres 3 tout afficher
  3811. void back_info(struct_back* sback,int i,int j,FILE* fp) {
  3812.   lien_back* const back = sback->lnk;
  3813.   const int back_max = sback->count;
  3814.   assertf(i >= 0 && i < back_max);
  3815.   if (back[i].status>=0) {
  3816.     char BIGSTK s[HTS_URLMAXSIZE*2+1024]; 
  3817.     s[0]='\0';
  3818.     back_infostr(sback,i,j,s);
  3819.     strcatbuff(s,LF);
  3820.     fprintf(fp,"%s",s);
  3821.   }
  3822. }
  3823.  
  3824. // infos backing
  3825. // j: 1 afficher sockets 2 afficher autres 3 tout afficher
  3826. void back_infostr(struct_back* sback,int i,int j,char* s) {
  3827.   lien_back* const back = sback->lnk;
  3828.   const int back_max = sback->count;
  3829.   assertf(i >= 0 && i < back_max);
  3830.   if (back[i].status>=0) {
  3831.     int aff=0;
  3832.     if (j & 1) {
  3833.       if (back[i].status==STATUS_CONNECTING) {
  3834.         strcatbuff(s,"CONNECT ");
  3835.       } else if (back[i].status==STATUS_WAIT_HEADERS) {
  3836.         strcatbuff(s,"INFOS ");
  3837.         aff=1;
  3838.       } else if (back[i].status==STATUS_CHUNK_WAIT || back[i].status==STATUS_CHUNK_CR) {
  3839.         strcatbuff(s,"INFOSC");             // infos chunk
  3840.         aff=1;
  3841.       }
  3842.       else if (back[i].status>0) {
  3843.         strcatbuff(s,"RECEIVE "); 
  3844.         aff=1; 
  3845.       }
  3846.     } 
  3847.     if (j & 2) {
  3848.       if (back[i].status==STATUS_READY) {
  3849.         switch (back[i].r.statuscode) {
  3850.         case 200:
  3851.           strcatbuff(s,"READY ");
  3852.           aff=1;
  3853.           break;
  3854.         case -1:
  3855.           strcatbuff(s,"ERROR ");
  3856.           aff=1;
  3857.           break;
  3858.         case -2:
  3859.           strcatbuff(s,"TIMEOUT ");
  3860.           aff=1;
  3861.           break;
  3862.         case -3:
  3863.           strcatbuff(s,"TOOSLOW ");
  3864.           aff=1;
  3865.           break;
  3866.         case 400:
  3867.           strcatbuff(s,"BADREQUEST ");
  3868.           aff=1;
  3869.           break;
  3870.         case 401: case 403:
  3871.           strcatbuff(s,"FORBIDDEN ");
  3872.           aff=1;
  3873.           break;
  3874.         case 404:
  3875.           strcatbuff(s,"NOT FOUND ");
  3876.           aff=1;
  3877.           break;
  3878.         case 500:
  3879.           strcatbuff(s,"SERVERROR ");
  3880.           aff=1;
  3881.           break;
  3882.         default:
  3883.           {
  3884.             char s2[256];
  3885.             sprintf(s2,"ERROR(%d)",back[i].r.statuscode);
  3886.             strcatbuff(s,s2);
  3887.           }
  3888.           aff=1;
  3889.         }
  3890.       }
  3891.     }
  3892.     
  3893.     if (aff) {
  3894.       {
  3895.         char BIGSTK s2[HTS_URLMAXSIZE*2+1024];
  3896.         sprintf(s2,"\"%s",back[i].url_adr); strcatbuff(s,s2);
  3897.         
  3898.         if (back[i].url_fil[0]!='/') strcatbuff(s,"/");
  3899.         sprintf(s2,"%s\" ",back[i].url_fil); strcatbuff(s,s2);
  3900.         sprintf(s,LLintP" "LLintP" ",(LLint)back[i].r.size,(LLint)back[i].r.totalsize); strcatbuff(s,s2);
  3901.       }
  3902.     }
  3903.   }
  3904. }
  3905.  
  3906. // -- backing --
  3907.  
  3908. #undef test_flush
  3909.